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;
}
}