Download ODBC Drivers for
Oracle, SQL Server, Salesforce, MongoDB, Access, Derby, InterBase, DB2, & more.
Learn More
/**********************************************************************
* FILENAME : CallSPUtil.c
*
* DESCRIPTION :
* Utility functions for Stored Procedure exmples:
* DropProcedure () - Drop strored procedure
* CreateProcedure () - Create stored proecdure
* ListProcedure() - Lookup and list stored procudure
*
* Procedure referenced are:
*
* {? = CALL Insert_Record (?, ?, ?, ?, ?, ?)}
* {CALL SelectRecords()}
* {CALL Find_Record(?)}
* {CALL Multi_Result_Sets()}
* {? = CALL InOutRet_Params (?, ?)}
* {? = CALL Find_ByID (?, ?)}
* {? = CALL Find_ByName (?, ?)}
* {? = CALL Edit_Record (?, ?, ?, ?, ?, ?)}
*
* See below for individual details.
*
* ODBC USAGE :
* DropProcedure() - Calls SQLExecDirect() with statement that
* checks procedure exist before dropping it.
* CreateProcedure() - Calls SQLExecDirect() to create a stored
* procedure.
* Insert_Record for use in these tests.
* List Procedure() - Used to show one of the above procedures
* is defined by lookup using SQLProcedures()
* and SQLBindCol() for the columns returned.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqlext.h>
#include <string.h>
#define BUFF_SIZE 255
#define FIRSTNAME_LEN 256
#define LASTNAME_LEN 256
#define ADDRESS_LEN 256
#define CITY_LEN 256
//
// Create Stored procedure
// Procedure is called either Insert_Record or Select_Records
//
SQLRETURN CreateProcedure (SQLHDBC hdbc, char *ProcName) {
SQLHSTMT hstmt = SQL_NULL_HSTMT; // Statement handle
SQLRETURN retcode = SQL_SUCCESS; // Return status
SQLCHAR strCreateSP [1024];
if (strcmp(ProcName, "Insert_Record") == 0) {
// Stored Procedure: Insert_Record
//
// Called by: CallSPINsertRec.c
//
// Usage {? = CALL Insert_Record (?, ?, ?, ?, ?, ?)}
//
// Has 7 Parameters - 1 - Proc return value (Prov RETURN value)
// 2-5 - Table columns (INPUT)
// 6 - Matching records count (OUTPUT)
// 7 - Total records Count (OUTPUT)
//
// Creates Stored Proc 'Insert_Record'
// Inserts record into TestTBL1 using params 2-5
// Generates result set of entire table
// Generates result set of records matching FirstName just inserted
// Returns number of records in table
// Returns number of records matching FirstName just inserted
// Function returns 100
//
strcpy(strCreateSP, "CREATE PROCEDURE Insert_Record ("
"@pFirstName nvarchar(256), @pLastName varchar(256), "
"@pAddress varchar(256), @pCity varchar(256), "
"@MatchingRecs int OUTPUT, @TotalRecs int OUTPUT) AS "
"INSERT INTO TestTBL1 (FirstName, LastName, Address, City) "
"VALUES (@pFirstName, @pLastName, @pAddress, @pCity); "
"SELECT * FROM TestTBL1 ORDER BY PersonID; "
"SELECT * FROM TestTBL1 WHERE FirstName=@pFirstName; "
"SELECT @MatchingRecs=count(*) FROM TestTBL1 WHERE "
"FirstName=@pFirstName; "
"SELECT @TotalRecs=count(*) FROM TestTBL1; "
"RETURN 100;");
} else if (strcmp(ProcName, "Select_Records") == 0) {
// Stored Procedure : 'Select_Records' (no param example)
// Called By : CallSP.c
//
// Usage {CALL SelectRecords()}
//
// Has no parameters
//
// Creates Stored Procedure 'Select_Records'
// Generates result set of entire table
//
strcpy (strCreateSP, "CREATE PROCEDURE Select_Records AS "
"SELECT PersonID, FirstName, LastName, Address, City "
"FROM TestTBL1");
} else if (strcmp(ProcName, "Find_Record") == 0) {
// Stored Procedure : 'Find_Record'
// Called By : CallSPWithParam.c
//
// Usage {CALL Find_Record(?)}
//
// Has 1 Input Parameter - pPersonID (INPUT)
//
// Creates stored procedure 'Find_Record'
// Generates result set of records matching pPersonID
//
strcpy (strCreateSP, "CREATE PROCEDURE Find_Record (@pPersonID INT) "
"AS SELECT PersonID, FirstName, LastName, Address, City "
"FROM TestTBL1 WHERE PersonID=@pPersonID");
} else if (strcmp(ProcName, "Multi_Result_Sets") == 0) {
// Stored Procedure : 'Multi_Result_Sets'
// Called By : CallSPMultiResultSet.c
//
// Usage {CALL Multi_Result_Sets()}
//
// Has no parameters
//
// Creates stored procedure Multi_Result_Sets
// Generates results set for all records in TestTBL1
// Generates results set for all records in TestTBLCopy
//
strcpy (strCreateSP, "CREATE PROCEDURE Multi_Result_Sets AS "
"SELECT PersonID, FirstName, LastName, Address, City "
"FROM TestTBL1; "
"SELECT PersonID, FirstName, LastName, Address, City "
"FROM TestTBL1Copy");
} else if (strcmp(ProcName, "InOutRet_Params") == 0) {
// Stored Procedure : 'InOutRet_Params'
// Called By : CallSPWithInOutParams.c
//
// Usage {? = CALL InOutRet_Params (?, ?)}
//
// Has 3 Parameters - 1 - Proc return value (Proc RETURN value)
// 2 - table field PersonID (INPUT)
// 3 - matching record count (OUTPUT)
//
// Creates stored procedure 'InOutRet_Params'
// Generates result set for records matching the input parameter
// Returns number of records in result set
// Function returns 100
//
strcpy(strCreateSP, "CREATE PROCEDURE InOutRet_Params ("
"@pPersonID int, @MatchingRecs int OUTPUT) AS "
"SELECT PersonID, FirstName, LastName, Address, City "
"FROM TestTBL1 WHERE PersonID=@pPersonID; "
"SELECT @MatchingRecs=count(*) FROM TestTBL1 WHERE "
"PersonID=@pPersonID; "
"RETURN 100;");
} else if (strcmp(ProcName, "Find_ByID") == 0) {
// Stored Procedure : Find_ByID
// Called By : CallSPFindID.c
//
// Usage {? = CALL Find_ByID (?, ?)}
//
// Uses 3 Parameters - 1 - return value
// 2 - pPersonIDs parameter array element (INPUT)
// 3 - pPersonIXs parameter array element (INPUT)
//
// Creates stored procedure Find_ByID
// Generates a result set that matches the pPersonID parameter
// Returns the pPersonIX. This can be used to tie the result set
// to the pPersonID that generated it
strcpy (strCreateSP, "CREATE PROCEDURE Find_ByID "
"(@pPersonID int, @pPersonIX int) AS SELECT PersonID, FirstName, "
"LastName, Address, City FROM TestTBL1 WHERE PersonID=@pPersonID; "
"RETURN @pPersonIX");
} else if (strcmp(ProcName, "Find_ByName") == 0) {
// Stored Procedure : Find_ByName
// Called By : CalLSPFindName.c
//
// Usage {? = CALL Find_ByName (?, ?)}
//
// Uses 3 Parameters - 1 - return value
// 2 - pFirstName parameter array element (INPUT)
// 3 - pPersonIXs parameter array element (INPUT)
//
// Creates stored procedure Find_ByName
// Generates a result set that matches the pFirstName parameter
// Returns the pPersonIX. This can be used to tie the result set
// to the pFirstName that generated it
strcpy (strCreateSP, "CREATE PROCEDURE Find_ByName ("
"@pFirstName varchar(2), @pPersonIX int) "
"AS SELECT PersonID, FirstName, LastName, Address, City "
"FROM TestTBL1 WHERE FirstName LIKE @pFirstName+'%'; "
"RETURN @pPersonIX");
} else if (strcmp(ProcName, "Edit_Record") == 0) {
// Stored Procedure : Edit_Record
// Called By : CallSPEditRecord.c
//
// Usage {? = CALL Edit_Record (?, ?, ?, ?, ?, ?)}
//
// Uses 7 Parameters - 1 - Proc return value - RETURNED
// 2 - Action - See below - INPUT
// 3 - RecordID - INPUT
// 4-7 - if action is SELECT
// - old column values - OUTPUT
// 4-7 - if action is UPDATE or INSERT
// - new column values - INPUT
// 4-7 - if action is DELETE
// - unused, delete is via RecordID
//
// Action values are SELECT RECORD 0
// UPDATE 1
// INSERT 2
// DELETE 3
// SELECT ALL 4
//
strcpy (strCreateSP, "CREATE PROCEDURE Edit_Record ("
"@action int, @pPersonID int OUTPUT, "
"@pFirstName nvarchar(256), @pLastName nvarchar(256), "
"@pAddress nvarchar(256), @pCity nvarchar(256)) "
"AS "
"IF (@action=0) BEGIN "
"SELECT PersonID, FirstName, LastName, Address, City "
"FROM TestTBL1 WHERE PersonID=@pPersonID; "
"END "
"ELSE "
"IF (@action=1) BEGIN "
"UPDATE TestTBL1 "
"SET FirstName=@pFirstName, LastName=@pLastName, "
"Address=@pAddress, City=@pCity "
"WHERE PersonID=@pPersonID; "
"END "
"ELSE "
"IF (@action=2) BEGIN "
"INSERT INTO TestTBL1 "
"(FirstName, LastName, Address, City) "
"VALUES (@pFirstName, @pLastName, @pAddress, @pCity);"
"SET @pPersonID=@@IDENTITY; "
"END "
"ELSE "
"IF (@action=3) BEGIN "
"DELETE FROM TestTBL1 WHERE PersonID=@pPersonID; "
"END "
"ELSE "
"IF (@action=4) BEGIN "
"SELECT PersonID, FirstName, LastName, Address, City "
"FROM TestTBL1 ORDER BY PersonID; "
"END "
"RETURN @action");
}
// Allocate a statement handle
retcode=SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_STMT)",
hstmt, SQL_HANDLE_STMT);
// Execute Create Procedure
retcode = SQLExecDirect (hstmt, strCreateSP, SQL_NTS);
CHECK_ERROR(retcode, "SQLExecDirect(CREATESP)",
hstmt, SQL_HANDLE_STMT);
exit:
// Free statement handle
if (hstmt != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return retcode;
}
//
// Function to drop existing stored proc. Either Insert_Record or
// Select_Records, which are the two we are using in these examples.
//
SQLRETURN DropProcedure (SQLHDBC hdbc, char *ProcName) {
SQLHSTMT hstmt = SQL_NULL_HSTMT; // Statement handle
SQLRETURN retcode = SQL_SUCCESS; // Return status
SQLCHAR strDropSP[1024];
sprintf (strDropSP, "IF EXISTS (SELECT * FROM sys.objects WHERE "
"type='P' AND name='%s') DROP PROCEDURE %s", ProcName, ProcName);
// Allocate a statement handle
retcode=SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_STMT)", hstmt,
SQL_HANDLE_STMT);
// Execute Drop Procedure
retcode = SQLExecDirect (hstmt, strDropSP, SQL_NTS);
CHECK_ERROR(retcode, "SQLExecDirect(SQL_HANDLE_STMT)", hstmt,
SQL_HANDLE_STMT);
exit:
// Free statement handle
if (hstmt != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return retcode;
}
//
// Function to list the stored proc we are using in this example.
// Uses SQLProcedures () to find stored proc Insert_Record or Select_Records.
//
SQLRETURN ListProcedure (SQLHDBC hdbc, char *ProcName) {
// Columns for binding to SQLProcedures() results set
SQLCHAR strProcedureCat[BUFF_SIZE];
SQLCHAR strProcedureSchema[BUFF_SIZE];
SQLCHAR strProcedureName[BUFF_SIZE];
SQLSMALLINT ProcedureType;
SQLLEN lenProcedureCat, lenProcedureSchema;
SQLLEN lenProcedureName, lenProcedureType;
int header=0;
SQLHSTMT hstmt = SQL_NULL_HSTMT; // Statement handle
SQLRETURN retcode = SQL_SUCCESS; // Return status
// Allocate a statement handle
retcode=SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_STMT)",
hstmt, SQL_HANDLE_STMT);
retcode = SQLProcedures (hstmt,
NULL, 0,
NULL, 0,
ProcName, strlen(ProcName));
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
// Bind columns in result set to buffers
// column 1 is the catalogue
SQLBindCol(hstmt, 1, SQL_C_CHAR, strProcedureCat,
sizeof(strProcedureCat), &lenProcedureCat);
// column 2 is the schema
SQLBindCol(hstmt, 2, SQL_C_CHAR, strProcedureSchema,
sizeof(strProcedureSchema), &lenProcedureSchema);
// column 3 is the procedure name
SQLBindCol(hstmt, 3, SQL_C_CHAR, strProcedureName,
sizeof(strProcedureName), &lenProcedureName);
// columns 4 to 7 are skipped
// column 8 is the procedure type
SQLBindCol(hstmt, 8, SQL_C_SHORT,&ProcedureType,
sizeof(ProcedureType), &lenProcedureType);
// fetch results (only expecting one row)
while (SQL_SUCCESS == retcode) {
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) {
extract_error("SQLFetch Error : ", hstmt, SQL_HANDLE_STMT);
}
if (header++==0) {
printf ("\nDSN : SQLSRV");
}
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
printf ("\nProcedure Cat : %s\n", strProcedureCat);
printf ("Procedure Schema : %s\n", strProcedureSchema);
printf ("Procedure Name : %s\n", strProcedureName);
printf ("Procedure Type : ");
switch (ProcedureType) {
case SQL_PT_PROCEDURE:
printf ("%s\n", "SQL_PT_PROCEDURE");
break;
case SQL_PT_FUNCTION:
printf ("%s\n", "SQL_PT_FUNCTION");
break;
case SQL_PT_UNKNOWN:
default:
printf ("%s\n", "SQL_PT_UNKNOWN");
break;
}
}
if (retcode==SQL_NO_DATA && header==1) {
printf ("(NO DATA)\n");
}
}
}
exit:
// Free statement handle
if (hstmt != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
// if last status is no data it is ok
if (retcode==SQL_NO_DATA) {
retcode=SQL_SUCCESS;
}
return retcode;
}
Download ODBC Drivers for
Oracle, SQL Server, Salesforce, MongoDB, Access, Derby, InterBase, DB2, & more.
Learn More