DSN8EDXD

Deletes a specified record from the sample XML database .

 /*********************************************************************
 * Module name = DSN8EDXD (DB2 sample program)                        *
 *                                                                    *
 * DESCRIPTIVE NAME = Sample XML record delete program                *
 *                                                                    *
 *    LICENSED MATERIALS - PROPERTY OF IBM                            *
 *    5675-DB2                                                        *
 *    (C) COPYRIGHT 1999, 2000 IBM CORP. ALL RIGHTS RESERVED.         *
 *                                                                    *
 *    STATUS = VERSION 9                                              *
 *                                                                    *
 * Function: Deletes a specified record from the sample XML database  *
 *                                                                    *
 * Notes:                                                             *
 *   Dependencies: Requires IBM C/C++ for z/OS                        *
 *                                                                    *
 *   Restrictions:                                                    *
 *                                                                    *
 * Module type: C program                                             *
 *   Processor: IBM C/C++ for z/OS                                    *
 * Module size: See linkedit output                                   *
 *  Attributes: Re-entrant and re-usable                              *
 *                                                                    *
 * Entry Point: DSN8EDXD                                              *
 *     Purpose: See Function                                          *
 *     Linkage: Standard z/OS linkage                                 *
 *                                                                    *
 *                                                                    *
 *  Parameters: None                                                  *
 *                                                                    *
 * Normal Exit: Return Code: 0000                                     *
 *              - Message: none                                       *
 *                                                                    *
 *  Error Exit: Return Code: 0012                                     *
 *              - Message: Unable to open <DD-name>                   *
 *              - Message: Unable to close <DD-name>                  *
 *              - Message: <formatted SQL text from DSNTIAR>          *
 *                                                                    *
 *    External References:                                            *
 *             - Routines/Services: DSNTIAR: DB2 msg text formatter   *
 *             - Data areas       : None                              *
 *             - Control blocks   : None                              *
 *                                                                    *
 *  Pseudocode:                                                       *
 *   DSN8EDXD:                                                        *
 *   - Call printGreeting to output the DSN8EDXD greeting             *
 *   - Call displayProductTable to list IDs of all products current-  *
 *     ly in the product table                                        *
 *   - Call readProductId to get the ID of the product to be deleted  *
 *   - Delete the record for the specified product ID                 *
 *     - If unexpected SQLCODE, call issueSqlError                    *
 *   - Call displayProductTable to list IDs of the products remaining *
 *     in the product table                                           *
 *   - Rollback the change to preserve the sample table               *
 *     - If unexpected SQLCODE, call issueSqlError                    *
 *   - Call displayProductTable to list IDs of all products in the    *
 *     product table                                                  *
 *   End DSN8EDXD                                                     *
 *                                                                    *
 *   printGreeting:                                                   *
 *   - Output the DSN8EDXD greeting                                   *
 *                                                                    *
 *   displayProductTable:                                             *
 *   - Open a cursor to get the ID of each item in the PRODUCT table  *
 *     - If unexpected SQLCODE, call issueSqlError                    *
 *   - Fetch and display each product id                              *
 *     - If unexpected SQLCODE, call issueSqlError                    *
 *   - Close the cursor                                               *
 *     - If unexpected SQLCODE, call issueSqlError                    *
 *                                                                    *
 *   readProductId:                                                   *
 *   - Open the file allocated to the PRODID DD                       *
 *     - If an error occurs, call issueDataSetOpeningError            *
 *   - Read the file                                                  *
 *     - If an error occurs, call issueDataSetReadingError            *
 *   - Call trimLeadingBlanks to remove leading blanks from the entry *
 *   - Call trimTrailingBlanks to remove trailing blanks from the     *
 *     entry                                                          *
 *   - Validate the length of the entry                               *
 *     - Call issueInvalidDataLengthError if length is unexpected     *
 *   - Close the file allocated to the PRODID DD                      *
 *     - If an error occurs, call issueDataSetClosingError            *
 *                                                                    *
 *   issueSqlError:                                                   *
 *   - call DSNTIAR to format the unexpected SQLCODE.                 *
 *                                                                    *
 *   issueDataSetOpeningError                                         *
 *   - Write a diagnostic message for error when opening a data set   *
 *                                                                    *
 *   issueDataSetReadingError                                         *
 *   - Write a diagnostic message for error when reading a data set   *
 *                                                                    *
 *   trimLeadingBlanks                                                *
 *   - Remove leading blanks from a string                            *
 *                                                                    *
 *   trimTrailingBlanks                                               *
 *   - Remove trailing blanks from a string                           *
 *                                                                    *
 *   issueInvalidDataLengthError                                      *
 *   - Write a diagnostic message when the length of inputted data    *
 *     is too long or too short                                       *
 *                                                                    *
 *   issueDataSetClosingError                                         *
 *   - Write a diagnostic message for error when closing a data set   *
 *                                                                    *
 * Change log:                                                        *
 *                                                                    *
 *********************************************************************/
 /**************************** Equates *******************************/
 #define         BLANK        ' '      /* Blank character            */
 #define         NULLCHAR     '\0'     /* Null character             */
 #define         LF           '\x25'   /* Line Feed character        */
 #define         RETNRM         0      /* Normal  return code        */
 #define         RETWRN         4      /* Warning return code        */
 #define         RETERR         8      /* Error return code          */
 #define         RETSEV        12      /* Severe error return code   */

 enum flag                  {No, Yes}; /* Settings for flags         */

 /********************** C library definitions ***********************/
 #include        <decimal.h>
 #include        <errno.h>
 #include        <stdio.h>
 #include        <stdlib.h>
 #include        <string.h>

 /******************* DB2 SQL Communication Area *********************/
 EXEC SQL INCLUDE SQLCA;

 /************************ DB2 Host Variables ************************/
 EXEC SQL BEGIN DECLARE SECTION;
   struct
     { struct
         { short int  PID_len;
           char       PID_data[10];
         }            PID;
       struct
         { short int  NAME_len;
           char       NAME_data[128];
         }            NAME;
       decimal(30,2)  PRICE;
       decimal(30,2)  PROMOPRICE;
       char       PROMOSTART[11];
       char       PROMOEND[11];
       SQL TYPE IS XML AS CLOB(1M) DESCRIPTION;
     } PRODUCT;
 EXEC SQL END DECLARE SECTION;

 /******************** DSN8EDXD Global Variables *********************/
 long int        rc               = 0; /* program return code        */

 /******************* DSN8EDXD Function Prototypes *******************/
 int main( int argc, char *argv[] );
 void clearBuffers( void );            /* Initialize work buffers    */
 void printGreeting( void );           /* Write welcome message      */
 void displayProductTable( void );     /* Show contents of prod tbl  */
 void readProductId( void );           /* Read product identifier    */
 void issueDataSetClosingError         /* Handler for ds close error */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   );
 void issueDataSetOpeningError         /* Handler for ds open error  */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   );
 void issueDataSetReadingError         /* Handler for ds read error  */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   );
 void issueInvalidDataLengthError      /* Handler for data len error */
   ( char            *DdName,          /* - in: identify of DD       */
     int             minLength,        /* - in: min valid length     */
     unsigned long   maxLength         /* - in: max valid length     */
   );
 void issueSqlError                    /* Handler for SQL error      */
   ( char            *locMsg           /* - in: Call location        */
   );
 void trimLeadingBlanks                /* Strip off leading blanks   */
   ( char            *string           /* - in: string to be trimmed */
   );
 void trimTrailingBlanks               /* Strip off trailing blanks  */
   ( char            *string           /* - in: string to be trimmed */
   );

 /*********************************************************************
 * List current PRODUCTS, then delete a product, then relist          *
 *********************************************************************/
 int main( int argc, char *argv[] )
   { printGreeting();                  /* Say hello                  */
                                       /* List PIDs already in table */
     printf( "(1) List the product IDs for items currently "
             "in the table:\n" );
     displayProductTable();            /* List the product ids       */

     if( rc < RETSEV )                 /* If all is well so far..    */
       { clearBuffers();               /* ..initialize work buffers  */
                                       /* ..and get prod id to delete*/
         readProductId();
       }

     if( rc < RETSEV )                 /* If all is well so far..    */
       { printf( "\n" );               /* ..advertise delete         */
         printf( "(2) Delete the record for product ID %s\n",
                 PRODUCT.PID.PID_data );
         EXEC SQL                      /* ..and delete the product   */
           DELETE FROM PRODUCT         /*   from the PRODUCT table   */
            WHERE PID = :PRODUCT.PID;

         if( SQLCODE != 0 )            /* ..report error, if any     */
           issueSqlError( "DSN8EDXD: Error "
                          "deleting product record" );
       }

     if( rc < RETSEV )                 /* If all is well so far..    */
       { clearBuffers();               /* ..initialize work buffers  */
                                       /* ..list PIDs now in table   */
         printf( "\n" );
         printf( "(3) List the product IDs for items "
                 "now in the table:\n" );
         displayProductTable();        /* ..list PIDs now in table   */
       }

     printf( "\n" );
     printf( "(4) Undo the change (for next time)\n" );
     EXEC SQL                          /* Rollback changes so program*/
       ROLLBACK;                       /* will run clean next time   */
     if( SQLCODE != 0 )                /* Report error, if any       */
       issueSqlError( "DSN8EDXD: Error "
                      "performing ROLLBACK" );

     if( rc < RETSEV )                 /* If all is well so far..    */
       { clearBuffers();               /* ..initialize work buffers  */
                                       /* ..list PIDs still in table */
         printf( "\n" );
         printf( "(5) List the product IDs for items "
                 "remaining in the table:\n" );
         displayProductTable();        /* ..list PIDs now in table   */
       }

     return( rc );                     /* Set return code and exit   */
   } /* end of main routine */


 void printGreeting( void )            /* Write welcome message      */
   /*******************************************************************
   * Writes a greeting when the program is started                    *
   *******************************************************************/
   { printf( "**************************************************"
             "******************************\n" );
     printf( "DSN8EDXD: Deletes a record from the PRODUCT table "
             "of the DB2 sample XML database\n" );
     printf( "**************************************************"
             "******************************\n" );
   } /* End of printGreeting */


 void displayProductTable( void )      /* Show contents of prod tbl  */
   /*******************************************************************
   * Lists the product ids currently in the PRODUCT table             *
   *******************************************************************/
   { EXEC SQL                          /* Cursor to get PIDs         */
       DECLARE productCursor
         CURSOR FOR
           SELECT PID
             FROM PRODUCT;

     EXEC SQL                          /* Open the cursor            */
       OPEN productCursor;
     if( SQLCODE != 0 )                /* Report error, if any       */
       issueSqlError( "DSN8EDXD: Error opening PRODUCT table cursor" );

     if( rc < RETSEV )                 /* If all is well so far..    */
       { EXEC SQL                      /* ..fetch the first row      */
           FETCH productCursor
            INTO :PRODUCT.PID;
                                       /* ..and process all rows     */
         while( SQLCODE == 0  &&  rc < RETSEV )
           { printf( "     %s\n",
                      PRODUCT.PID.PID_data );

             EXEC SQL
               FETCH productCursor
                INTO :PRODUCT.PID;
           }                           /* ..report error, if any     */
         if( SQLCODE != 0 && SQLCODE != 100 )
           issueSqlError( "DSN8EDXD: Error "
                          "fetching from PRODUCT table cursor" );
       }

     EXEC SQL                          /* Close the cursor           */
       CLOSE productCursor;
     if( SQLCODE != 0 )                /* Report error, if any       */
       issueSqlError( "DSN8EDXD: Error closing PRODUCT table cursor" );

   } /* end of displayProductTable */


 void clearBuffers( void )             /* Initialize work buffers    */
   /*******************************************************************
   * Initializes work buffers for next use                            *
   *******************************************************************/
   { memset( PRODUCT.PID.PID_data,
             NULLCHAR,
             sizeof(PRODUCT.PID.PID_data) );
     PRODUCT.PID.PID_len = 0;
   } /* End of clearBuffers */


 void readProductId( void )            /* Read product identifier    */
   /*******************************************************************
   * Reads id of product description to be deleted from the PRODID DD *
   *******************************************************************/
   { FILE           *prodIdFile;       /* Ptr to PRODID DD           */
     char           prodIdDD[12];      /* DD handle                  */
     char           prodIdRec[80];     /* PRODID file input record   */
     short int      recordLength  = 0; /* Length of record           */
     unsigned short moreRecords = Yes; /* EOF indicator              */

     strcpy( prodIdDD,"DD:PRODID" );

     PRODUCT.PID.PID_len = 0;
     errno = 0;                        /* Clear LE errno             */
     prodIdFile = fopen( prodIdDD,
                         "rb,lrecl=80,type=record" );
     if( prodIdFile == NULL )          /* Report error, if any       */
       issueDataSetOpeningError( prodIdDD,errno );

     if( rc < RETSEV )
       { recordLength
           = fread( prodIdRec,         /* Read into PRODID rec area  */
                    1,                 /* ..1 record                 */
                    80,                /* ..of 80 bytes              */
                    prodIdFile );      /* ..from PRODID file         */

         if( ferror(prodIdFile) )      /* Handle IO errors           */
            issueDataSetReadingError( prodIdDD,errno );

         else if(feof(prodIdFile)) /* Handle EOF                     */
            moreRecords = No;
                                       /* Discard bytes 73-80 and    */
         else                          /* strip off trailing blanks  */
           { strncat( PRODUCT.PID.PID_data,prodIdRec,72 );
             trimLeadingBlanks( PRODUCT.PID.PID_data );
             trimTrailingBlanks( PRODUCT.PID.PID_data );
           }
                                       /* Don't overfill return area */
         if( rc < RETSEV && strlen(PRODUCT.PID.PID_data) > 10 )
           issueInvalidDataLengthError( "PRODID",1,10 );
       }

     if( rc < RETSEV )                 /* Close file                 */
       { PRODUCT.PID.PID_len = strlen(PRODUCT.PID.PID_data);
         if( fclose( prodIdFile ) != 0 )
           issueDataSetClosingError( prodIdDD,errno );
       }

   } /* end of readProductId */


 void issueDataSetClosingError         /* Handler for ds close error */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   )
   /*******************************************************************
   * Called when a TSO data set cannot be closed                      *
   *******************************************************************/
   { printf( "ERROR: Unable to close %s\n", DDname );
     printf( "%s \n",strerror(LEerrno) );
     printf( "-----> Processing halted\n" );
     rc = RETSEV;
   } /* end of issueDataSetClosingError */


 void issueDataSetOpeningError         /* Handler for ds open error  */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   )
   /*******************************************************************
   * Called when a TSO data set cannot be opened                      *
   *******************************************************************/
   { printf( "ERROR: Unable to open %s\n", DDname );
     printf( "%s \n",strerror(LEerrno) );
     printf( "-----> Processing halted\n" );
     rc = RETSEV;
   } /* end of issueDataSetOpeningError */


 void issueDataSetReadingError         /* Handler for ds read error  */
   ( char            *DDname,          /* - in: name of errant DD    */
     int             LEerrno           /* - in: LE diagnostic errno  */
   )
   /*******************************************************************
   * Called when a TSO data set cannot be read                        *
   *******************************************************************/
   { printf( "ERROR: Unable to read %s\n", DDname );
     printf( "%s \n",strerror(LEerrno) );
     printf( "-----> Processing halted\n" );
     rc = RETSEV;
   } /* end of issueDataSetReadingError */


 void issueInvalidDataLengthError      /* Handler for data len error */
   ( char            *DdName,          /* - in: identify of DD       */
     int             minLength,        /* - in: min valid length     */
     unsigned long   maxLength         /* - in: max valid length     */
   )
   /*******************************************************************
   * Called when the length of data read from a DSN8EDXD input file   *
   * (identified by DdName) does not fall within the valid bounds for *
   * size (minLength and maxLength).                                  *
   *******************************************************************/
   { printf( "ERROR: The length of the data read for read from the %s "
                    "DD \n",DdName );
     printf( "       does not fall within the required bounds of %i "
                    "and %u\n",minLength,maxLength );
     printf( "-----> Processing halted\n" );
     rc = RETSEV;
   } /* end of issueInvalidDataLengthError */


 #pragma linkage(dsntiar, OS)
 void issueSqlError                    /* Handler for SQL error      */
   ( char *locMsg                      /* - in: Call location        */
   )
   /*******************************************************************
   * Called when an unexpected SQLCODE is returned from a DB2 call    *
   *******************************************************************/
   { struct      error_struct {        /* DSNTIAR message structure  */
       short int   error_len;
       char        error_text[10][80];
       }         error_message = {10 * 80};

     extern short int dsntiar( struct      sqlca         *sqlca,
                               struct      error_struct  *msg,
                               int                       *len );

     short int   DSNTIARrc;            /* DSNTIAR Return code        */
     int         j;                    /* Loop control               */
     static int  lrecl = 80;           /* Width of message lines     */

     /*****************************************************************
     * print the locator message                                      *
     *****************************************************************/
     printf( "ERROR: %-80s\n", locMsg );
     printf( "-----> Processing halted\n" );

     /*****************************************************************
     * format and print the SQL message                               *
     *****************************************************************/
     DSNTIARrc = dsntiar( &sqlca, &error_message, &lrecl );
     if( DSNTIARrc == 0 )
       for( j = 0; j <= 10; 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" );
       }

     /*****************************************************************
     * set severe error code                                          *
     *****************************************************************/
     rc = RETSEV;

   } /* end of issueSqlError */


 void trimLeadingBlanks                /* Strip off leading blanks   */
   ( char            *string           /* - in: string to be trimmed */
   )
   /*******************************************************************
   * Strips trailing blanks from a string                             *
   *******************************************************************/
   { int             i;
     char           *p;
     for( i = 0; i < strlen(string) && string[i] == ' '; i++ );
     p = &string[i];
     strcpy( string,p );
   } /* end of trimLeadingBlanks */


 void trimTrailingBlanks               /* Strip off trailing blanks  */
   ( char            *string           /* - in: string to be trimmed */
   )
   /*******************************************************************
   * Strips trailing blanks from a string                             *
   *******************************************************************/
   { int             i;
     for( i = strlen(string) - 1; string[i] == ' '; i-- );
     string[++i] = '\0';
   } /* end of trimTrailingBlanks */