DSN8EDXR

Fetches, formats and displays the description record for a specified product id in the sample XML database .

 /*********************************************************************
 * Module name = DSN8EDXR (DB2 sample program)                        *
 *                                                                    *
 * DESCRIPTIVE NAME = Sample XML record display program               *
 *                                                                    *
 *    LICENSED MATERIALS - PROPERTY OF IBM                            *
 *    5675-DB2                                                        *
 *    (C) COPYRIGHT 1999, 2000 IBM CORP. ALL RIGHTS RESERVED.         *
 *                                                                    *
 *    STATUS = VERSION 9                                              *
 *                                                                    *
 * Function: Fetches, formats and displays the description record     *
 *           for a specified product id in 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: DSN8EDXR                                              *
 *     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:                                                       *
 *   DSN8EDXR:                                                        *
 *   - Call printGreeting to output the DSN8EDXR greeting             *
 *   - Call readProductId to get the ID of the product to be displayed*
 *   - Call getProductDescriptionRecord to fetch the description of   *
 *     the product for the inputted product ID.                       *
 *   - Call displayProductDescriptionRecord to format and display     *
 *     the product description record                                 *
 *   End DSN8EDXR                                                     *
 *                                                                    *
 *   printGreeting:                                                   *
 *   - Output the DSN8EDXR greeting                                   *
 *                                                                    *
 *   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            *
 *                                                                    *
 *   getProductDescriptionRecord:                                     *
 *   - Fetch the description of the product for the inputted product  *
 *     ID.                                                            *
 *     - If unexpected SQLCODE, call issueSqlError                    *
 *                                                                    *
 *   displayProductDescriptionRecord:                                 *
 *   - Call getToken to locate the product section                    *
 *     - If not found, issue an diagnostic message                    *
 *   - Call getToken to locate the description section and return the *
 *     product attributes                                             *
 *     - If not found, issue an diagnostic message                    *
 *   - Call getToken for locate and return the name and setting of    *
 *     each element in the product description section                *
 *   - Output the product and description sections followed by the    *
 *     name and setting of each element in the description section    *
 *                                                                    *
 *   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   *
 *                                                                    *
 *   getToken                                                         *
 *   - Locate the search argument in the buffer and optionally        *
 *     return the tokens up to and including the search argument      *
 *                                                                    *
 * 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;

   SQL TYPE IS XML AS CLOB(1M) workBuffer;
   char           *workBufPtr;
 EXEC SQL END DECLARE SECTION;

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

 typedef struct item
   { char        *element;             /* ptr to element name        */
     char        *value;               /* ptr to string value        */
     int         allocated;            /* mem alloc indicator        */
   }           item;

 /*simple structure to hold a list of elements and values*/
 typedef struct prodList
   { char        *productElement;
     int         elements;             /* num elements in the list   */
     item        itemList[10];         /* list of elements           */
   }           prodList;

     prodList        prodDesc;         /* gets product description   */


 /******************* DSN8EDXR Function Prototypes *******************/
 int main( int argc, char *argv[] );
 void printGreeting( void );           /* Write welcome message      */
 void readProductId( void );           /* Read product identifier    */
 void getProductDescriptionRecord      /* Fetch product descr record */
   ( void
   );
 void displayProductDescriptionRecord  /* Show the prod desc record  */
   ( void
   );
 void clearBuffers( void );            /* Initialize work buffers    */
 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 */
   );
 char *getToken                        /* Gets token from a string   */
   ( char            *tokPtrR,         /* -in: Ptr to start of token */
     char            *string,          /* -in: String to break on    */
     unsigned short  returnToken,      /* -in: token suppression     */
     char            *token            /* -out: Token                */
   );

 /*********************************************************************
 * Get a product ID, then fetch and display its product description   *
 *********************************************************************/
 int main( int argc, char *argv[] )
   {
     clearBuffers();                   /* Initialize work areas      */

     printGreeting();                  /* Say hello                  */

     readProductId();                  /* Read in the product id of  */
                                       /* the record to be displayed */

     if( rc < RETSEV )                 /* If all is well so far..    */
       { getProductDescriptionRecord();/* ..fetch product desc record*/
       }
     if( rc < RETSEV )                 /* If all is well so far..    */
       {                               /* ..show the product descr.  */
         printf( "Display the product description for product "
                 "ID %s\n",PRODUCT.PID.PID_data );
         displayProductDescriptionRecord();
         printf( " \n" );
       }

     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( "DSN8EDXR: Fetches and displays the description of "
             "a specified item in the\n"
             "          PRODUCT table of the DB2 sample XML "
                       "database\n" );
     printf( "**************************************************"
             "******************************\n" );
   } /* End of printGreeting */


 void clearBuffers( void )             /* Initialize work buffers    */
   /*******************************************************************
   * Initializes work buffers for next use                            *
   *******************************************************************/
   { memset( PRODUCT.DESCRIPTION.data,
             NULLCHAR,
             sizeof(PRODUCT.DESCRIPTION.data) );
     PRODUCT.DESCRIPTION.length = 0;

     memset( workBuffer.data,
             NULLCHAR,
             sizeof(workBuffer.data) );
     workBuffer.length = 0;
   } /* End of clearBuffers */


 void readProductId( void )            /* Read product identifier    */
   /*******************************************************************
   * Reads id of product description to be displayed from 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 getProductDescriptionRecord( void )
   /*******************************************************************
   * Gets the product description record to be displayed              *
   *******************************************************************/
   {

     EXEC SQL                          /* Fetch DESCRIPTION record  */
       SELECT DESCRIPTION              /* for requested product id  */
         INTO :PRODUCT.DESCRIPTION
         FROM PRODUCT
        WHERE PID = :PRODUCT.PID;

     if( SQLCODE != 0 )                /* Report error, if any       */
       issueSqlError( "DSN8EDXR: Error selecting from PRODUCT table" );

   }


 void displayProductDescriptionRecord
   ( void
   )
   /*******************************************************************
   * Shows the selected product description record                    *
   *******************************************************************/
   { int             i;                /* for array indexing         */
     char            *tokPtr;          /* string ptr for token parser*/

     workBufPtr = &workBuffer.data[0];

     tokPtr = getToken( PRODUCT.DESCRIPTION.data,
                        "<product ",
                        No,
                        NULL );
     if( tokPtr == NULL )
       { printf("Error Parsing product XML Could not find product\n");
         rc = RETERR;
       }
     else
       { tokPtr = getToken( tokPtr,
                            "<description>",
                            Yes,
                            workBufPtr );

         if( tokPtr == NULL )
           { printf("Error Parsing product XML "
                    "Could not find description\n");
             rc = RETERR;
           }
         else
           { trimLeadingBlanks( workBufPtr );
             trimTrailingBlanks( workBufPtr );
             prodDesc.productElement = workBufPtr;
             workBufPtr = workBufPtr + strlen(workBufPtr) + 1;
           }
       }

     /*****************************************************************
     * Parse out each element in the <description>. Data looks like:  *
     * <elem-1>data-1</elem-1>...<elem-n>data-n</elem-n></description>*
     *****************************************************************/
     for( i=0; i < 10 && rc == RETNRM && tokPtr != NULL; i++ )
       { tokPtr = getToken( tokPtr,"<",No,NULL );
         if( tokPtr != NULL )
           { tokPtr = getToken( tokPtr,
                                ">",
                                Yes,
                                workBufPtr );
           }
         if( tokPtr != NULL )
           { if( !strcmp( workBufPtr,"/description"))
               tokPtr = NULL;
             else
               { prodDesc.itemList[i].element = workBufPtr;
                 workBufPtr = workBufPtr + strlen(workBufPtr) + 1;
               }
           }
         if( tokPtr != NULL )
           { tokPtr = getToken( tokPtr,
                                "<",
                                Yes,
                                workBufPtr );
           }
         if( tokPtr != NULL )
           { prodDesc.itemList[i].value = workBufPtr;
             workBufPtr = workBufPtr + strlen(workBufPtr) + 1;
             prodDesc.itemList[i].allocated = No;
           }
       }
     prodDesc.elements = --i;

     printf( "<product %s\n  <description>\n",
             prodDesc.productElement );
     for( i=0; i < prodDesc.elements; i++ )
       { printf( "    <%s>%s</%s>\n",
                 prodDesc.itemList[i].element,
                 prodDesc.itemList[i].value,
                 prodDesc.itemList[i].element );
       }
     printf( "  </description>\n" );
     printf( "</product>\n" );

   } /* end of displayProductDescriptionRecord */


 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 DSN8EDXR 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 */


 char *getToken                        /* Gets token from a string   */
   ( char            *tokPtrR,         /* -in: Ptr to start of token */
     char            *string,          /* -in: String to break on    */
     unsigned short  returnToken,      /* -in: token suppression     */
     char            *token            /* -out: Token                */
   )
   /*******************************************************************
   * Locates string 'string' in source string pointed to by 'tokPtrR'.*
   * Places token in 'token' if 'returntoken' is Yes on function call.*
   * Returns pointer past location of 'string' if 'string' found,     *
   * otherwise null.                                                  *
   *******************************************************************/
   { char    *tokPtrL = tokPtrR;
     int     tokLen;

     tokPtrR = strstr( tokPtrL,string );
     if( tokPtrR == NULLCHAR )
       return NULL;
     else
       { if( returnToken == Yes )
         { tokLen = tokPtrR-tokPtrL;
             strncpy( token,tokPtrL,tokLen );
             token[tokLen] = '\0';
           }
         tokPtrR = tokPtrR + strlen(string);
         return tokPtrR;
       }
   }