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