DSN8ED1
Pass Db2 commands received from standard input to stored procedure DSN8ED2 for execution.
/********************************************************************/
/* Module name = DSN8ED1 (sample program) */
/* */
/* DESCRIPTIVE NAME = Stored procedure result set requester pgm */
/* */
/* LICENSED MATERIALS - PROPERTY OF IBM */
/* 5645-DB2 */
/* (C) COPYRIGHT 1998 IBM CORP. ALL RIGHTS RESERVED. */
/* */
/* STATUS = VERSION 6 */
/* */
/* Function = */
/* */
/* Pass DB2 commands received from standard input to */
/* stored procedure DSN8ED2 for execution. Receive the */
/* command results from DSN8ED2 as result set. Unload the */
/* result set and print the contents to standard output. */
/* */
/* Dependencies = None */
/* */
/* Restrictions = */
/* */
/* 1. DB2 commands must be preceded by a hyphen and */
/* followed by a semicolon. Lines with an asterisk */
/* in the first column or two hyphens as the first */
/* nonblank characters are interpreted as comment */
/* lines. Two hyphens placed after the command text in */
/* in a line indicate that the rest of the line is */
/* comments only. */
/* */
/* 2. A command may be no more than 4096 bytes. */
/* */
/* Input = */
/* 1. A single input parameter that indicates the location */
/* of the stored procedure. The contents must be a */
/* valid DB2 location name of at most 16 characters. */
/* */
/* 2. Lines of length INPUTL from standard input. */
/* Only the first INPUSED bytes are used. Lines are */
/* considered to be either command text or comments. */
/* Command text begins with a hyphen and ends with a */
/* semicolon. Comments begin with an asterisk in */
/* column one or two hyphens as the first two nonblank */
/* characters. Command text may span lines, but comment */
/* text may not. */
/* */
/* Output = */
/* Lines of length OUTLEN to standard output. */
/* Each line contains one of the following: */
/* a. Command text. */
/* b. Results returned by the DB2 for MVS/ESA command */
/* processor after the command is issued. */
/* */
/* Module type = C program */
/* Processor = */
/* ADMF Precompiler */
/* C/370 */
/* Module size = See linkedit output */
/* Attributes = Not reentrant or reusable */
/* */
/* Entry point = DSN8ED1 */
/* Purpose = See Function */
/* Linkage = Standard MVS program invocation, one parameter. */
/* */
/* Exit normal = */
/* */
/* Return code 0 on normal completion. */
/* */
/* Normal messages = */
/* */
/* *** Input statement: <DB2 command input statement text> */
/* *** IFI return area: <Results of DB2 command execution> */
/* */
/* */
/* Exit-error = */
/* */
/* Return code = 4 - Warnings occurred. */
/* - The DB2 for MVS/ESA Instrumentation Facility Interface */
/* (IFI) invocation of the DB2 command resulted in a */
/* return code 4. The accompanying reason code indicates */
/* the specific problem. */
/* */
/* Return code = 8 - Errors occurred. */
/* - The DB2 for MVS/ESA Instrumentation Facility Interface */
/* (IFI) invocation of the DB2 command resulted in a */
/* return code 8. The accompanying reason code indicates */
/* the specific problem. */
/* */
/* Return code = 12 - Severe errors occurred. */
/* - Input parameter 1 did not contain the name of the */
/* DB2 server where the stored procedure resides. */
/* - The input dataset (SYSIN) did not contain any data. */
/* - Command input did not begin with a hyphen. */
/* - Command input was not ended with a semicolon. */
/* - An input statement contained more than STMTMAX */
/* bytes. */
/* - Connection to the stored procedure location failed. */
/* - The SQL CALL statement to the stored procedure failed. */
/* - The DB2 for MVS/ESA Instrumentation Facility Interface */
/* (IFI) invocation of the DB2 command resulted in a */
/* return code 12. The accompanying reason code indicates */
/* the specific problem. */
/* - The call to the stored procedure, DSN8ED2, succeeded */
/* but DSN8ED2 experienced SQL problems. The formatted */
/* SQL error message appears in SYSPRINT. */
/* - The call to the stored procedure, DSN8ED2, succeeded */
/* but no result set was returned. SYSPRINT messages */
/* should provide more information. */
/* - A result set was returned by DSN8ED2 but one of the */
/* following occurred (see SYSPRINT messages for details):*/
/* - The locator variable could not be associated with */
/* the result set. */
/* - The result set cursor could not be allocated */
/* - No data could be fetched from the result set cursor. */
/* */
/* Abend codes = None */
/* */
/* Error messages = */
/* - *** ERROR: No server name provided - DSN8ED1 ended. */
/* - *** ERROR: No input records found - DSN8ED1 ended. */
/* - *** ERROR: Syntax for DB2 command is invalid. */
/* *** A valid command ends with a semicolon. */
/* - *** ERROR: Syntax for DB2 command is invalid. */
/* *** A valid command begins with a hyphen. */
/* - *** ERROR: Statement length is greater than the ____ */
/* character maximum. */
/* - *** ERROR: Connection to server <location> was unsuc- */
/* cessful. */
/* - *** ERROR: Call to stored procedure DSN8ED2 failed; */
/* diagnostics follow. */
/* - *** ERROR: The following diagnostics were returned by */
/* stored procedure DSN8ED2. */
/* - *** ERROR: DSNTIAR could not format the message. */
/* SQLCODE is ____, SQLERRM is ___________ ... */
/* - *** WARNING: Call to stored procedure DSN8ED2 succeeded */
/* but no result set was returned. */
/* - *** WARNING: IFI error codes returned by DSN8ED2. */
/* Return code=___, reason code=____ from */
/* IFI request. */
/* - *** WARNING: ____ records were lost because the IFI */
/* return area in stored procedure DSN8ED2 */
/* is too small to accomodate this request. */
/* ** Increase the IFI return area (RETURN_LEN) */
/* in DSN8ED2 and then recompile/relink/rebind */
/* before resubmitting this request. */
/* */
/* - *** Syntax for DB2 command is invalid. */
/* *** A valid command must begin with a hyphen. */
/* */
/* - *** Statement length is greater than the <STMTMAX> */
/* character maximum. */
/* - *** Connection to <location> unsuccessful. */
/* *** SQLCODE is <sqlcode>. */
/* - *** Call to DSN8ED2 unsuccessful. */
/* *** SQLCODE is <sqlcode>. */
/* - *** Insufficient space to receive all output from IFI */
/* return area. */
/* - *** Return code=<return code>, reason code=<reason code> */
/* from IFI request. */
/* - *** Severe error occurred. Program is terminating. */
/* */
/* External references = */
/* Routines/services = */
/* none */
/* Data areas = */
/* none */
/* Control blocks = */
/* SQLCA - SQL communication area */
/* */
/* Pseudocode = */
/* */
/* DSN8ED1: */
/* - Extract the name of the DB2 server where stored procedure */
/* DSN8ED2 resides from input parameter number 1. */
/* - Call build_DB2_command to create a logical DB2 command record*/
/* from one or more records from SYSIN. */
/* - If a command was created successfully, do the following until*/
/* all input has been processed or severe errors occur. */
/* - Call connect_to_sp_server to connect to the DB2 server */
/* specified in the first input parameter. */
/* - Call send_DB2_command_to_sp to invoke stored procedure */
/* DSN8ED2 to process the command. */
/* - Call output_results_from_sp to unload the result set */
/* from DSN8ED2 to SYSPRINT. */
/* - Call build_DB2_command to create the next logical DB2 */
/* command record from SYSIN records. */
/* End DSN8ED1 */
/* */
/* build_DB2_command: */
/* - Read a record from SYSIN */
/* - Do the following until either a full command is built, end */
/* of file is reached, or an error occurs: */
/* - if the first byte of the record is '*' or the first two */
/* nonblank bytes of the record are '--' then the whole */
/* record is a comment. Disregard it. */
/* - if '--' is encountered after nonblanks are found then the */
/* rest of the record is a comment and can be disregarded. */
/* - else if a semicolon is found inside a delimited string */
/* call copy_byte_to_cmd_buf to add it to the command string. */
/* - a delimited string is one that starts but has not yet */
/* terminated with a single quote or a double quote */
/* - else if a semicolon is found outside a delimited string */
/* then the command is complete. */
/* - else if a nonblank is found then call copy_byte_to_cmd_buf */
/* to add it to the command string. */
/* - else if a blank is found inside a delimited string then */
/* call copy_byte_to_cmd_buf to add it to the command string. */
/* - else if a blank is found outside a delimited string and */
/* the preceding byte was nonblank then call copy_byte_to_ */
/* cmd_buf to add it to the command string. */
/* - else if a blank is found outside a delimited string and */
/* the preceding byte was blank then disregard the blank. */
/* - if the input record is exhausted before a terminating */
/* semicolon is found, read the next input record. */
/* - When a command is created successfully, call echo_DB2_command*/
/* to output the reformatted command. */
/* - Check the command to ensure that it starts with a hypen. */
/* End build_DB2_command */
/* */
/* copy_byte_to_cmd_buf */
/* - append the current byte of the input record to the end of */
/* the command string and update length of command string. */
/* - if command string exceeds buffer size, issue a message and */
/* end DSN8ED1. */
/* End copy_byte_to_cmd_buf */
/* */
/* echo_DB2_command */
/* - output the reformatted DB2 command to SYSPRINT */
/* End echo_DB2_command */
/* */
/* connect_to_sp_server */
/* - invoke SQL to CONNECT to the DB2 server where stored proc- */
/* edure DSN8ED2 resides. */
/* - if the CONNECT fails, issue a message and end DSN8ED1. */
/* End connect_to_sp_server */
/* */
/* send_DB2_command_to_sp */
/* - invoke SQL to call stored procedure DSN8ED2 to process the */
/* contents of the command buffer. */
/* - analyze the resultant SQLCODE, IFI return and result codes, */
/* and buffer overload and error parameters returned by DSN8ED2.*/
/* End send_DB2_command_to_sp */
/* */
/* output_results_from_sp */
/* - associate a DB2 locator variable with the result set from */
/* stored procedure DSN8ED2 */
/* - allocate a cursor to the result set */
/* - fetch each row from the result set and output it to SYSPRINT */
/* End output_results_from_sp */
/* */
/* sql_error */
/* - invoke DSNTIAR to format the current SQL code and print the */
/* messages to SYSPRINT */
/* - if DSNTIAR cannot detail the code, output the SQLCODE and */
/* SQLERRM to SYSPRINT
/* End sql_error */
/* */
/* Change activity = */
/* none */
/********************************************************************/
/********************** C library definitions ***********************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**************************** Constants *****************************/
#define INPUTL 81 /* Length of input line */
#define INPUSED 72 /* Bytes used in an input line*/
#define LOCLEN 16 /* Length of input parm (loc) */
#define OUTLEN 81 /* Length of output line */
#define RETWRN 4 /* Warning return code */
#define RETERR 8 /* Error return code */
#define RETSEV 12 /* Severe error return code */
#define STMTMAX 4096 /* Maximum statement length */
#define ASTERISK '*' /* Comment indicator */
#define BLANK ' ' /* Blank */
#define HYPHEN '-' /* Hyphen */
#define NULLCHAR '\0' /* Null character */
#define QUOTE '\'' /* Quotation mark */
#define DQUOTE '"' /* Double quote */
#define SEMICOLON ';' /* SQL stmt terminator */
enum flag {No, Yes}; /* Settings for flags */
/********************** Program Argument List ***********************/
char *parms[]; /* Contains input parameter */
/********************** Standard Input/Output ***********************/
FILE *sysin; /* Input statements */
char input[INPUTL]; /* Current input data */
char *inres; /* Result of gets invocation */
FILE *sysprint; /* Command results/error msgs */
/************************ Working variables *************************/
short int c; /* pointer to command buffer */
enum flag dquotflag; /* '"' delimiter status */
short int i; /* pointer to input buffer */
short int j; /* miscellaneous counter, ptr */
enum flag endstr; /* End of statement flag */
enum flag input_eof; /* End of input data flag */
enum flag quoteflag; /* "'" delimiter status */
/************************ DB2 Host Variables ************************/
EXEC SQL BEGIN DECLARE SECTION;
char db2loc2[17]; /* Remote DB2 location name */
long int ifca_ret_hex; /* Return code from IFI call */
long int ifca_res_hex; /* Reason code from IFI call */
long int xs_bytes_hex; /* No. of bytes not returned */
long int rc; /* All-purpose return var */
struct {
short int sp_err_blen; /* Error msg buffer length */
char sp_err_txt[880]; /* Error msg text */
} sp_err_buf; /* Error message buffer from */
/* stored procedure */
short int sperind1; /* Indicator vars for parm 1 */
short int sperind2; /* Indicator vars for parm 2 */
short int sperind3; /* Indicator vars for parm 3 */
short int sperind4; /* Indicator vars for parm 4 */
short int sperind5; /* Indicator vars for parm 5 */
struct {
short int cmdlen; /* Statement length */
char cmdtxt[4096]; /* Statement text */
} cmdbuf; /* Statement buffer passed to */
/* stored procedure */
/* Result set locator */
static volatile SQL TYPE IS RESULT_SET_LOCATOR *DSN8ED2_rs_loc;
long int rs_sequence; /* Result set table data sequ */
char rs_data[80]; /* Result set data buffer */
/* - length is OUTLEN - 1 */
EXEC SQL END DECLARE SECTION;
/******************** DB2 SQL Communication Area ********************/
EXEC SQL INCLUDE SQLCA;
/*********************************************************************
**********************************************************************
** main routine **
**********************************************************************
*********************************************************************/
int main( int argc, char *argv[] ) /*proc*/
{
/*******************************************************************
* initialize working variables *
*******************************************************************/
cmdbuf.cmdlen = 0; /* Nothing in command buf yet */
input_eof = No; /* Not at end of input */
rc = 0; /* No errors yet */
sperind1 = -1; /* Clear null indicator var 1 */
sperind2 = -1; /* Clear null indicator var 2 */
sperind3 = -1; /* Clear null indicator var 3 */
sperind4 = -1; /* Clear null indicator var 4 */
sperind5 = -1; /* Clear null indicator var 5 */
/*******************************************************************
* get input parameter (name of server where stored proc resides) *
*******************************************************************/
for( j=1; j<argc; j++ ) /* break out the input parms */
parms[j] = argv[j];
for( j=0; j<LOCLEN; j++ ) /* Extract name of DB2 server */
db2loc2[j] = *(parms[1]+j); /* where sp resides */
if( db2loc2[1] == BLANK ) /* If no server specified, */
{ /* issue error */
printf( " *** ERROR: No server name provided - DSN8ED1 ended.\n" );
rc = RETSEV;
}
db2loc2[j]=NULLCHAR; /* Null-terminate the string */
/*******************************************************************
* build the first DB2 command from one or more input records *
*******************************************************************/
if( rc < RETSEV )
{
build_DB2_command();
if( input_eof == Yes && rc < RETSEV )
{
printf( " *** ERROR: No input records found - DSN8ED1 ended.\n");
rc = RETSEV;
}
}
/******************************************************************/
/* If a command was built successfully, connect to the DB2 server */
/* where the stored procedure resides, send the command to the */
/* stored procedure, output the results, and build the next com- */
/* mand, if any. */
/******************************************************************/
while( input_eof == No && rc < RETSEV )
{
connect_to_sp_server(); /* connect to the server */
if( rc < RETSEV ) /* if successful */
send_DB2_command_to_sp(); /* invoke the stored proc */
if( rc < RETSEV ) /* if successful */
output_results_from_sp(); /* out the results */
if( rc < RETSEV ) /* if successful */
build_DB2_command(); /* process the next input */
}
printf( " \n \n *** DSN8ED1 completed; highest return code was %d\n",
rc );
return( rc ); /* put return code in ctl blk */
} /* end of main program */
/********************************************************************
*********************************************************************
** Build a DB2 command from one or more physical input records **
*********************************************************************
********************************************************************/
build_DB2_command() /*proc*/
{
/*******************************************************************
* initialize working variables *
*******************************************************************/
for( i=0; i<INPUTL; i++ ) /* Blank the input array */
input[i] = ' ';
c = 0; /* marks pos'n in command buf */
cmdbuf.cmdlen = 0; /* no. of bytes in cmd buffer */
dquotflag = No; /* flags delimiter stat of '"'*/
endstr = No; /* flags end of log inp record*/
i = 0; /* marks pos'n in input buffer*/
quoteflag = No; /* flags delimiter stat of "'"*/
/*******************************************************************
* read the first physical record of the command from input *
*******************************************************************/
inres = gets( input );
if( inres == NULL ) /* If end of file reached */
input_eof = Yes; /* then all finished */
/*******************************************************************
* parse the current input record for DB2 command parts *
*******************************************************************/
while( endstr == No && input_eof == No && rc < RETSEV )
{
/*****************************************************************
* If 1st char in a line is '*' -OR- the 1st two non-blank chars *
* in a line are '--', this is a comment line. Don't copy it to *
* the command buffer; request next line. *
*****************************************************************/
if( i == 0 && input[0] == ASTERISK )
i = INPUSED;
else if( cmdbuf.cmdlen == 0
&& input[0] == HYPHEN && input[1] == HYPHEN )
i = INPUSED;
/*****************************************************************
* Otherwise, this must be a command line. Parse it into the com-*
* mand buffer while looking for delimiters and the end of stmt. *
*****************************************************************/
else
while( i < INPUSED && endstr == No && rc < RETSEV )
{
if( input[i] == DQUOTE ) /* if double quote found */
if( dquotflag == Yes ) /* and is already a delimiter*/
dquotflag = No; /* note end of delimited str*/
else if( quoteflag == No ) /* else if it's not delimited*/
dquotflag = Yes; /* then it's a delimiter */
if( input[i] == QUOTE ) /* if single quote found */
if( quoteflag == Yes ) /* and is already a delimiter*/
quoteflag = No; /* -note end of delimited str*/
else if( dquotflag == No ) /* else if it's not delimited*/
quoteflag = Yes; /* then it's a delimiter */
if( input[i] == HYPHEN /* if '--' found in current */
&& input[i+1] == HYPHEN /* and next byte */
&& i < INPUSED /* not at end of input line */
&& quoteflag == No /* and not in a delimited */
&& dquotflag == No ) /* strng then rest is comment*/
i = INPUSED; /* ignore it; rqst next line*/
else if( input[i] == SEMICOLON/* else if semicolon found */
&& quoteflag == No /* and it's not delimited */
&& dquotflag == No ) /* then command is complete */
endstr = Yes; /* fall through */
else if( input[i] != BLANK ) /* else if non-blank found */
copy_byte_to_cmd_buf(); /* copy it to command buffer */
else if( input[i] == BLANK /* else if blank found */
&& ( quoteflag == Yes /* and it's in a delimited */
|| dquotflag == Yes ) ) /* string */
copy_byte_to_cmd_buf(); /* copy it to command buffer*/
else if( input[i] == BLANK /* else if blank found */
&& c > 0 /* and something's in cmd buf*/
&& cmdbuf.cmdtxt[c-1]!=BLANK)/* and prev cmd byte nonblank */
copy_byte_to_cmd_buf(); /* copy it to command buffer*/
else; /* swallow all other blanks */
i++; /* bump pos'n in input record */
} /* end while( i<INPUSED && endstr == No && rc<RETSEV ) */
/*****************************************************************
* if current physical record is exhausted but the current log- *
* ical record is still incomplete, get the next physical record *
*****************************************************************/
if( i >= INPUSED && endstr == No && rc < RETSEV )
{
for( i=0; i<INPUTL; i++ ) /* Blank the input array */
input[i] = ' ';
i = 0; /* reset pointer to input buff*/
inres = gets( input ); /* Read the next physical rec */
if( inres == NULL ) /* If end of file reached */
{ /* current logical rec inmplt*/
input_eof = Yes; /* don't ask for more */
printf( " *** ERROR: Syntax for DB2 command is invalid.\n");
printf( " *** A valid command ends with a" );
printf( " semicolon.\n" );
rc = RETSEV; /* stop the program */
}
}
} /* end while( endstr == No && input_eof == No && rc < RETSEV ) */
/*******************************************************************
* display the reformatted command (if one exists) *
*******************************************************************/
if( cmdbuf.cmdlen > 0 )
echo_DB2_command();
/*******************************************************************
* verify that the command has a valid syntax *
*******************************************************************/
if( endstr == Yes && input_eof == No && rc < RETSEV )
if( cmdbuf.cmdtxt[0] != HYPHEN )
{
printf( " *** ERROR: Syntax for DB2 command is invalid.\n");
printf( " *** A valid command begins with a hyphen.\n" );
rc = RETSEV;
}
} /* end of build_DB2_command() */
/*********************************************************************
**********************************************************************
** Copy the current byte of current input line to command buffer **
**********************************************************************
*********************************************************************/
copy_byte_to_cmd_buf() /*proc*/
{
cmdbuf.cmdtxt[c++] = input[i];
cmdbuf.cmdlen = c;
/*******************************************************************
* if entry is too long for command buffer, issue message and quit *
*******************************************************************/
if( cmdbuf.cmdlen >= STMTMAX )
{
printf( " *** ERROR: Statement length is greater than the" );
printf( " %d character maximum.\n",STMTMAX );
rc = RETSEV;
}
} /* end of copy_byte_to_cmd_buf() */
/*********************************************************************
**********************************************************************
** Connect to the server where the stored procedure resides **
**********************************************************************
*********************************************************************/
connect_to_sp_server() /*proc*/
{
EXEC SQL CONNECT TO :db2loc2;
if( SQLCODE != 0 )
{
printf( " *** ERROR: Connection to server %s was unsuccessful.\n",
db2loc2 );
sql_error( " *** Connection to server unsuccessful" );
rc = RETSEV;
}
} /* end of connect_to_sp_server() */
/*********************************************************************
**********************************************************************
** Process the current DB2 command built from the input file **
**********************************************************************
*********************************************************************/
send_DB2_command_to_sp() /*proc*/
{
sperind1 = 0; /* tell DB2 to transmit */
/* contents of parm 1 */
EXEC SQL CALL DSN8.DSN8ED2( :cmdbuf :sperind1,
:ifca_ret_hex :sperind2,
:ifca_res_hex :sperind3,
:xs_bytes_hex :sperind4,
:sp_err_buf :sperind5 );
/*******************************************************************
* verify the SQL return code returned by the stored procedure *
*******************************************************************/
if( SQLCODE == 0 )
{
printf( " *** WARNING: Call to stored procedure DSN8ED2" );
printf( " succeeded\n" );
printf( " but no result set was returned.\n" );
if( rc < RETERR )
rc = RETERR;
}
else if( SQLCODE == 466 )
{
printf( " *** A result set was returned by stored procedure" );
printf( " DSN8ED2.\n" );
}
else
{
printf( " *** ERROR: Call to stored procedure DSN8ED2 failed;" );
printf( " diagnostics follow.\n" );
sql_error( "*** Stored procedure call unsuccessful." );
rc = RETSEV;
}
/*******************************************************************
* verify the IFI return code returned by the stored procedure *
*******************************************************************/
if( sperind2 != -1 && ifca_ret_hex != 0 )
{
printf( " *** WARNING: IFI error codes returned by DSN8ED2.\n" );
printf( " *** Return code=%0X ", ifca_ret_hex );
printf( " *** reason code=%0X from IFI request.\n", ifca_res_hex );
if( ifca_ret_hex > rc )
rc = ifca_ret_hex;
}
/*******************************************************************
* if IFI return buffer was too small, output a message *
*******************************************************************/
if( sperind4 != -1 && xs_bytes_hex != 0 )
{
printf( " *** WARNING: %d bytes were lost", xs_bytes_hex );
printf( " because the IFI return area in stored\n" );
printf( " *** procedure DSN8ED2 is too small" );
printf( " to accomodate this request.\n" );
printf( " *** ** Increase the IFI return area" );
printf( " (RETURN_LEN) in DSN8ED2 and then\n" );
printf( " *** recompile/relink/rebind before" );
printf( " resubmitting the request.\n" );
if( rc < RETWRN )
rc = RETWRN;
}
/*******************************************************************
* output any data from the error message buffer *
*******************************************************************/
if( sperind5 != -1 )
{
printf( " *** ERROR: The following diagnostics were returned by" );
printf( " stored procedure DSN8ED2.\n \n" );
for( j = 0; j < sp_err_buf.sp_err_blen; j++ )
printf( "%c",sp_err_buf.sp_err_txt[j] );
printf( "\n" );
if( rc < RETSEV )
rc = RETSEV;
}
} /* end of send_DB2_command_to_sp() */
/*********************************************************************
**********************************************************************
** Write out the DB2 command that has been built from input records **
**********************************************************************
*********************************************************************/
echo_DB2_command() /*proc*/
{
short int c; /* local ptr to command buffer*/
short int k,kk,l; /* counters and loop control */
printf( " \n \n *** Input Statement:\n" );
c = 0;
/*******************************************************************
* calculate no. of full print lines the cmd uses and print them *
*******************************************************************/
kk = cmdbuf.cmdlen / (OUTLEN - 1);
for( k=1; k<=kk; k++ )
{
printf( " " );
for( l=0; l<(OUTLEN-1); l++ )
{
printf( "%c",cmdbuf.cmdtxt[c++] );
}
printf( "\n" );
}
/*******************************************************************
* calculate no. of partial print lines the cmd uses; print them *
*******************************************************************/
kk = cmdbuf.cmdlen % (OUTLEN - 1);
if( kk > 0 )
{
printf( " " );
for( k=1; k<=kk; k++ )
{
printf( "%c",cmdbuf.cmdtxt[c++] );
}
printf( "\n" );
}
} /* end of echo_DB2_command() */
/*********************************************************************
**********************************************************************
** Output the contents of the result set returned by the stored **
** procedure. **
**********************************************************************
*********************************************************************/
output_results_from_sp() /*proc*/
{
/*******************************************************************
* local initialization *
*******************************************************************/
for(j=0; j<(OUTLEN-1); j++) /* Blank the input array */
rs_data[j] = BLANK; /* Initialize result string */
rs_sequence = 0; /* Initialize data sequence */
printf( " \n \n *** IFI return area:\n" );
/*******************************************************************
* associate a locator variable with the result *
*******************************************************************/
EXEC SQL ASSOCIATE LOCATOR /* Associate the result set */
(:DSN8ED2_rs_loc) /* locator with a host var. */
WITH PROCEDURE DSN8.DSN8ED2; /* */
if (SQLCODE != 0 ) /* If unsuccessful then */
{ /* - Say so */
sql_error( "*** Associate result set locator call unsuccessful." );
/* - Print the sqlcode */
rc = RETSEV; /* - Flush remainder of proc */
} /* */
/*******************************************************************
* allocate the result set cursor *
*******************************************************************/
if( rc < RETSEV ) /* Or if okay so far then */
{ /* */
EXEC SQL ALLOCATE DSN8ED2_RS_CSR /* - Allocate a cursor to read*/
CURSOR FOR /* - Allocate a cursor to read*/
RESULT SET :DSN8ED2_rs_loc; /* the result set locator */
if (SQLCODE != 0 ) /* - If unsuccessful then */
{ /* - Say so */
sql_error( "*** Allocate result set cursor call unsuccessful." );
/* - Print the sqlcode */
rc = RETSEV; /* - Flush remainder of proc*/
} /* */
} /* */
/*******************************************************************
* fetch first row from the result set *
*******************************************************************/
if( rc < RETSEV ) /* Or if okay so far then */
{
EXEC SQL FETCH DSN8ED2_RS_CSR /* - Fetch first row (if any) */
INTO :rs_sequence, :rs_data; /* from the result set csr */
if (SQLCODE != 0 ) /* - If unsuccessful then */
{ /* - Say so */
sql_error("*** Priming fetch of result set cursor unsuccessful");
/* - Print the sqlcode */
rc = RETSEV; /* - Flush remainder of proc*/
} /* */
} /* */
/*******************************************************************
* output the contents of the result set *
*******************************************************************/
while(SQLCODE == 0 && rc < RETSEV) /* Or if okay so far then */
{ /* until all lines processed */
printf( " %s\n", rs_data ); /* -- Output current line */
/* */
EXEC SQL FETCH DSN8ED2_RS_CSR /* -- Get the next one from */
INTO :rs_sequence, :rs_data; /* the result set cursor */
} /* */
/*******************************************************************
* check for successful processing of result set *
*******************************************************************/
if (SQLCODE != 100 && rc < RETSEV) /* If unsuccessful then */
{ /* - Say so */
sql_error( "*** Fetch of result set cursor unsuccessful." );
/* - Print the sqlcode */
rc = RETSEV; /* - Set return code */
} /* */
} /* end of output_results_from_sp() */
/*********************************************************************
**********************************************************************
** SQL error handler **
**********************************************************************
*********************************************************************/
#pragma linkage(dsntiar, OS)
sql_error( char locmsg[] ) /*proc*/
{
#define DATA_DIM 10 /* Number of message lines */
struct error_struct { /* DSNTIAR message structure */
short int error_len;
char error_text[DATA_DIM][OUTLEN-1];
} error_message = {DATA_DIM * (OUTLEN-1)};
extern short int dsntiar( struct sqlca *sqlca,
struct error_struct *msg,
int *len );
short int rc; /* DSNTIAR Return code */
int j; /* Loop control */
static int lrecl = OUTLEN - 1; /* Width of message lines */
/*******************************************************************
* print the locator message *
*******************************************************************/
printf( " %.80s\n", locmsg );
/*******************************************************************
* format and print the SQL message *
*******************************************************************/
rc = dsntiar( &sqlca, &error_message, &lrecl );
if( rc == 0 )
for( j=0; j<=DATA_DIM; 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" );
}
} /* end of sql_error */