/**********************************************************************
* FILENAME : CallSPInsertRecs.c
*
* DESCRIPTION :
* Illustrates using a stored procedure to performs several
* actions relating to inserting a record into a table. It
* shows how to set up input and output parameters and how to
* return a status value from the procedure.
*
* Calls a stored procedure as follows:
*
* {? = CALL Insert_Record (?, ?, ?, ?, ?, ?)}
*
* ODBC USAGE :
* Drops and recreates a procedure 'Insert_Record'
* Confirms the procedure exists via SQLProcedures ()
* Uses SQLBindParameter() to bind data to the 7
* parameters used in the stored procedure.
*
* 7 Parameters - 1 - Proc return value - RETURNED
* 2-5 - table fields - INPUT
* 6 - matching record count - OUTPUT
* 7 - total records - OUTPUT
* Loops asking for user inout for the 4 INPUT fields until
* blank FirstName (param 2) is entered:
* Uses SQLExecute () to execute stored proc which adds
* new person record into TestTBL1 using user input
* Returns all records in the table, ordered by ID
* Returns all records that match new record firstname
* Returns number of matching records
* Returns number of records in table
* Returns 100 as function return value
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqlext.h>
#include <string.h>
#include "util.c"
#include "CallSPUtil.c"
int main () {
SQLHENV henv = SQL_NULL_HENV; // Environment
SQLHDBC hdbc = SQL_NULL_HDBC; // Connection handle
SQLHSTMT hstmt = SQL_NULL_HSTMT; // Statement handle
SQLRETURN retcode; // Return status
// Declare call to stored proc with 7 parameter markers
SQLCHAR * strCallSP = "{? = CALL Insert_Record (?, ?, ?, ?, ?, ?)}";
char * strProcName = "Insert_Record";
SQLSMALLINT columns; // Number of columns in result-set
int i, count;
// Stored proc paramaters, output variables and return variable.
SQLCHAR strFirstName[FIRSTNAME_LEN], strLastName[LASTNAME_LEN];
SQLCHAR strAddress[ADDRESS_LEN], strCity[CITY_LEN];
SWORD RetParam = 1, MatchingRecs = 1, TotalRecs = 1;
SQLLEN lFirstName, lLastName, lAddress, lCity;
SQLLEN lRetParam, lMatchingRecs, lTotalRecs;
// Allocate an environment handle
retcode=SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
CHECK_ERROR(retcode, "SQLAllocHandle(ENV)", henv, SQL_HANDLE_ENV);
// Set ODBC Version
retcode=SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
(void *) SQL_OV_ODBC3, 0);
CHECK_ERROR(retcode, "SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION)",
henv, SQL_HANDLE_ENV);
// Allocate a connection handle
retcode=SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_DBC)",
hdbc, SQL_HANDLE_DBC);
// Connect to data source
retcode=SQLDriverConnect(hdbc, NULL, "DSN=DATASOURCE;", SQL_NTS, NULL,
0, NULL, SQL_DRIVER_COMPLETE);
CHECK_ERROR(retcode, "SQLDriverConnect(DATASOURCE)",
hdbc, SQL_HANDLE_DBC);
// Drop previous procedure called Insert_Record
retcode = DropProcedure (hdbc, strProcName);
// Create new procedure called Insert_Record
retcode = CreateProcedure (hdbc, strProcName);
// Use SQLPRocedures() to show Insert_Record it now available
retcode = ListProcedure (hdbc, strProcName);
// Allocate a statement handle
retcode=SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_STMT)",
hstmt, SQL_HANDLE_STMT);
// Bind parameteres. The order is the order in which they appear
// 1st is return parameter
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_SSHORT,
SQL_INTEGER, 0, 0, &RetParam, 0, &lRetParam);
CHECK_ERROR(retcode, "SQLBindParameter(1)", hstmt, SQL_HANDLE_STMT);
// 2nd is FirstName passed as input
retcode = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_CHAR, FIRSTNAME_LEN, 0, strFirstName,
FIRSTNAME_LEN, &lFirstName);
CHECK_ERROR(retcode, "SQLBindParameter(2)", hstmt, SQL_HANDLE_STMT);
// 3rd is LastName passed as input
retcode = SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_CHAR, LASTNAME_LEN, 0, strLastName,
LASTNAME_LEN, &lLastName);
CHECK_ERROR(retcode, "SQLBindParameter(3)", hstmt, SQL_HANDLE_STMT);
// 4th is Address passed as input
retcode = SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_CHAR, ADDRESS_LEN, 0, strAddress,
ADDRESS_LEN, &lAddress);
CHECK_ERROR(retcode, "SQLBindParameter(4)", hstmt, SQL_HANDLE_STMT);
// 5th is City passed as input
retcode = SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR,
SQL_CHAR, CITY_LEN, 0, strCity,
CITY_LEN, &lCity);
CHECK_ERROR(retcode, "SQLBindParameter(5)", hstmt, SQL_HANDLE_STMT);
// 6th is returned as outout and is the number of records that match
// the FirstName of the record inserted. E.g. number of Johns, if
// John was just inserted.
// This is generated by the SELECT @MatchingRecs=count(*) FROM
// TestTBL1 WHERE FirstName=@pFirstName part of the stored proc.
retcode = SQLBindParameter(hstmt, 6, SQL_PARAM_OUTPUT, SQL_C_SSHORT,
SQL_INTEGER, 0, 0, &MatchingRecs, 0,
&lMatchingRecs);
CHECK_ERROR(retcode, "SQLBindParameter(6)", hstmt, SQL_HANDLE_STMT);
// 7th is used to return the total number of records in the table. This
// is generated by the SELECT @TotalRecs=count(*) FROM TestTBL1 part
// of the stored proc.
retcode = SQLBindParameter(hstmt, 7, SQL_PARAM_OUTPUT, SQL_C_SSHORT,
SQL_INTEGER, 0, 0, &TotalRecs, 0, &lTotalRecs);
CHECK_ERROR(retcode, "SQLBindParameter(7)", hstmt, SQL_HANDLE_STMT);
retcode = SQLPrepare (hstmt, strCallSP, SQL_NTS);
CHECK_ERROR(retcode, "SQLPrepare(SQL_HANDLE_STMT)",
hstmt, SQL_HANDLE_STMT);
SQLLEN indicator, RowCount;;
char *buf=malloc (255);
// Loop inserting and displaying records until blank firstname entered
while (1) {
// Initialise buffers
memset (strFirstName, ' ', FIRSTNAME_LEN);
memset (strLastName, ' ', LASTNAME_LEN);
memset (strAddress, ' ', ADDRESS_LEN);
memset (strCity, ' ', CITY_LEN);
// Get data to insert, quit loop on blank firstname
getStr ("\nFirst Name", strFirstName, FIRSTNAME_LEN, 'N');
if (strlen(strFirstName) == 0) break;
getStr ("Last Name", strLastName, LASTNAME_LEN, 'N');
getStr ("Address ", strAddress, ADDRESS_LEN, 'N');
getStr ("City ", strCity, CITY_LEN, 'N');
lFirstName=strlen(strFirstName);
lLastName=strlen(strLastName);
lAddress=strlen(strAddress);
lCity=strlen(strCity);
retcode = SQLExecute (hstmt);
CHECK_ERROR(retcode, "SQLExecute(SQL_HANDLE_STMT)",
hstmt, SQL_HANDLE_STMT);
// For a more generic example, use SQLDescribeCol here to
// find column names ...
printf ("\nPersonID Firstname Surname Address City");
printf ("\n-------- --------- ------- ------- ----");
// This loop will execute twice, once for each of the SELECT * FROM
// statements in the stored proc. The first gives all records in the
// table, the second gives all records that match the firstname of the
// record just added (so there should be at least one).
// Note, the while SQLFetch returns the records from a result set,
// SQLMoreResults indicates whether there are more results sets.
do {
// SQLNumResultCols() returns number of columns in result set.
// if non zero use SQLFetch until SQL_NO_DATA returned
retcode=SQLNumResultCols(hstmt, &columns);
CHECK_ERROR(retcode, "SQLNumResultCols()", hstmt, SQL_HANDLE_STMT);
printf ("\nColumns : %i", columns);
if (columns > 0) {
printf ("\nStart Fetch ...");
while (SQLFetch(hstmt) != SQL_NO_DATA) {
// Loop through the columns
memset (buf, ' ', 255);
printf ("\n");
for (i = 1; i <= columns; i++) {
// Retrieve column data for column i as a string
retcode = SQLGetData(hstmt, i, SQL_C_CHAR,
buf, 255, &indicator);
if (SQL_SUCCEEDED(retcode)) {
// Output NULL if indicator suggests so
if (indicator == SQL_NULL_DATA) {
strcpy (buf, "NULL");
}
buf=rtrim(buf, ' ');
if (i==1)
printf("%-8s ", buf);
else
printf("%-12s ", buf);
}
}
}
printf ("\nEnd Fetch ...\n");
} else {
// SQLRowCount returns number of rows affected by
// INSERT, UPDATE, DELETE or (if the driver provides) the
// number of rows returned by a SELECT
retcode=SQLRowCount(hstmt, &RowCount);
CHECK_ERROR(retcode, "SQLRowCount()", hstmt, SQL_HANDLE_STMT);
printf ("\nRow count is : %i\n", (int) RowCount);
}
} while (SQLMoreResults(hstmt) == SQL_SUCCESS);
// Output values for matching records and total records
printf("Matching Records : %d\n", MatchingRecs);
printf("Total Records : %d\n", TotalRecs);
// Output return parameter, set to 100 (SQL_NO_DATA) in the stored
// proc, but could be used for something more meaningful.
printf("Return Parameter : %d\n", RetParam);
}
exit:
// free temporary buffer used for formatting record data
free (buf);
printf ("\nComplete.\n");
// Free handles
// Statement
if (hstmt != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
// Connection
if (hdbc != SQL_NULL_HDBC) {
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
// Environment
if (henv != SQL_NULL_HENV)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
Further information