Try-Catch doesn't catch exception - c++

I would like to catch an exception, which occures in my code using Try/Catch like this:
try
{
//my code
}
catch(std::exception &e)
{
std::wcout <<"An exception occured"<<" "<<e.what();
}
but such a structure dosn't catch the exception in my code. I recieve an exception from Visual studio in this line:
retcode = bcp_init(hdbc1,"information1", NULL,NULL, DB_IN);
and not from my try/catch.
here you can see my whole code:
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include<tchar.h>
#include<iostream>
#include<sqlncli.h>
#include<exception>
using namespace std;
SQLHENV henv = SQL_NULL_HENV;
HDBC hdbc1 = SQL_NULL_HDBC, hdbc2 = SQL_NULL_HDBC;
SQLHSTMT hstmt2 = SQL_NULL_HSTMT;
void Cleanup() {
if (hstmt2 != SQL_NULL_HSTMT)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt2);
if (hdbc1 != SQL_NULL_HDBC) {
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
}
if (hdbc2 != SQL_NULL_HDBC) {
SQLDisconnect(hdbc2);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc2);
}
if (henv != SQL_NULL_HENV)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
int main() {
try
{
RETCODE retcode;
// BCP variables.
char *terminator = "\0";
// bcp_done takes a different format return code because it returns number of rows bulk copied
// after the last bcp_batch call.
DBINT cRowsDone = 0;
// Set up separate return code for bcp_sendrow so it is not using the same retcode as SQLFetch.
RETCODE SendRet;
// Allocate the ODBC environment and save handle.
retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(Env) Failed\n\n");
Cleanup();
return(9);
}
// Notify ODBC that this is an ODBC 3.0 app.
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLSetEnvAttr(ODBC version) Failed\n\n");
Cleanup();
return(9);
}
// Allocate ODBC connection handle, set bulk copy mode, and connect.
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLAllocHandle(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
retcode = SQLSetConnectAttr(hdbc1, SQL_COPT_SS_BCP, (void *)SQL_BCP_ON, SQL_IS_INTEGER);
if ( (retcode != SQL_SUCCESS_WITH_INFO) && (retcode != SQL_SUCCESS)) {
printf("SQLSetConnectAttr(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
// sample uses Integrated Security, create the SQL Server DSN using Windows NT authentication
SQLWCHAR dsn[30] = L"mssqltest"; //Name DNS
SQLWCHAR user[10] = L"di_test";
SQLWCHAR pass[10] = L"di_test";
// SQLWCHAR tb[20]=L"information1";
retcode = SQLConnectW(hdbc1, (SQLWCHAR *)dsn, SQL_NTS, (SQLWCHAR *) user, SQL_NTS, (SQLWCHAR *) pass, SQL_NTS);
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("SQLConnect() Failed\n\n");
Cleanup();
return(9);
}
// TRYODBC(hdbc1, SQL_HANDLE_DBC, retcode);
// Initialize the bulk copy.
retcode = bcp_init(hdbc1,"information1", NULL,NULL, DB_IN);
/* TRYODBC(hdbc1, SQL_HANDLE_DBC, retcode);*/
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("bcp_init(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
//Define our array
DBINT custIDs[] ={1,2,3,4};
// Bind the program variables for the bulk copy.
if( bcp_bind(hdbc1, (BYTE *)&custIDs, 0, sizeof(DBINT), NULL,0, SQLINT4, 2)==FAIL)
{
retcode=-1;
}
if ( (retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO) ) {
printf("bcp_bind(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
// Could normally use strlen to calculate the bcp_bind cbTerm parameter, but this terminator
// is a null byte (\0), which gives strlen a value of 0. Explicitly give cbTerm a value of 1.
if( bcp_bind(hdbc1,(LPCBYTE) custIDs, 2, SQL_VARLEN_DATA, NULL,0, SQL_C_NUMERIC, 3)==FAIL)
{
retcode=-1;
}
if ( (retcode != SUCCEED) ) {
printf("bcp_bind(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
if ( (SendRet = bcp_sendrow(hdbc1) ) != SUCCEED ) {
printf("bcp_sendrow(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
cRowsDone = bcp_done(hdbc1);
if ( (cRowsDone == -1) ) {
printf("bcp_done(hdbc1) Failed\n\n");
Cleanup();
return(9);
}
printf("Number of rows bulk copied after last bcp_batch call = %d.\n", cRowsDone);
// Cleanup.
SQLFreeHandle(SQL_HANDLE_STMT, hstmt2);
SQLDisconnect(hdbc1);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
SQLDisconnect(hdbc2);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc2);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
catch(std::exception &e)
{
std::wcout <<"An exception occured"<<" "<<e.what();
}
}

You're not seeing a C++ exception. This is what Microsoft calls a SEH exception, which is actually a program crash. You can catch those (search on MSDN for __try and __except) but in general this is like the Java NullPointerException - it's a programming error, and no error handling is going to fix that.
Also, Visual Studio, if set to "break on all exceptions", will break when an exception occurs that will be handled in a try/catch too. If you just continue execution, it'll go to the corresponding catch & be handled. If this is what happens, turn off the "break on all exceptions". It will stop anyway on unhandled ones.

C++ is not Java. There is no such thing as a universal base class exception, so std::exception is just a base class for all exceptions thrown by the Standard Library.
If you want to catch any exception (and not any strange error that could happen), you can use catch(...).
As shown by SingerOfTheFall's comment, you can use C++11 std::current_exception to inspect the exception object.

Related

Visual Studio C++ connect to DB2

I'm trying to write a C ++ program using a database - IBM DB2 Express-C. Also, I use Visual Studio 2015. Via IBM OLE DB Provider for DB2 my Visual Studio successfully connected to DB2. I can see tables and all OK:
Then I created new C++ program, I successfully connect several header files, some from them I found in my DB2 directory, for example sqlcli1.h
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <stdlib.h>
#include <string.h>
#include <sqlcli1.h>
#include <windows.h>
The following is the code of the main program. In which I am trying to connect to the database to which successfully was connected the Visual Studio.
#include "stdafx.h"
int main()
{
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
SQLCHAR * OutConnStr = (SQLCHAR *)malloc(255);
SQLSMALLINT * OutConnStrLen = (SQLSMALLINT *)malloc(255);
// Allocate environment handle
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
// Set the ODBC version environment attribute
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
// Allocate connection handle
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
// Connect to data source
retcode = SQLConnect(hdbc, (SQLWCHAR*) "DATABASE=SAMPLE;HOSTNAME=localhost", SQL_NTS, (SQLWCHAR*) "db2admin", SQL_NTS, (SQLWCHAR*) "password", SQL_NTS);
if (retcode != SQL_SUCCESS) {
printf(">--- Error while connecting to database:");
printf("SQLConnect: %d\n", retcode);
}
// Allocate statement handle
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
printf("\nAllocate Connection handle successfully.");
// Process data
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
SQLDisconnect(hdbc);
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
system("pause");
return 0;
}
There are no errors at compile time, but can not connect to the database.When program execution comes to the block.
// Connect to data source
retcode = SQLConnect(hdbc, (SQLWCHAR*) "DATABASE=SAMPLE;HOSTNAME=localhost", SQL_NTS, (SQLWCHAR*) "db2admin", SQL_NTS, (SQLWCHAR*) "password", SQL_NTS);
if (retcode != SQL_SUCCESS) {
printf(">--- Error while connecting to database:");
printf("SQLConnect: %d\n", retcode);
}
I see >--- Error while connecting to database:SQLConnect:-2
What does it means? what I am doing is wrong? I also tried it:
retcode = SQLConnect(hdbc, (SQLWCHAR*) "SAMPLE", SQL_NTS, (SQLWCHAR*) "db2admin", SQL_NTS, (SQLWCHAR*) "password", SQL_NTS);
But it also does not work. May be the second argument should look like in some other way?
Changed
I tried use this function SQLGetDiagRec I created some variables
SQLWCHAR SqlState[6], SQLStmt[100], Msg[SQL_MAX_MESSAGE_LENGTH];
SQLINTEGER NativeError;
SQLSMALLINT i, MsgLen;
SQLRETURN rc1, rc2;
I also change my connect block
// Connect to data source
retcode = SQLConnect(hdbc, (SQLWCHAR*) "SAMPLE", SQL_NTS, (SQLWCHAR*) "db2admin", SQL_NTS, (SQLWCHAR*) "password", SQL_NTS);
if (retcode != SQL_SUCCESS) {
printf(">--- Error while connecting to database:");
printf("SQLConnect: %d\n", retcode);
if ((retcode == SQL_SUCCESS_WITH_INFO) || (retcode == SQL_ERROR)) {
// Get the status records.
i = 1;
while ((rc2 = SQLGetDiagRec(SQL_HANDLE_STMT, hdbc, i, SqlState, &NativeError,
Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA) {
cout << SqlState;
cout << i;
cout << NativeError;
cout << Msg;
i++;
}
}
}
But nothing has changed. Does anyone have any idea?
If a call to any CLI function doesn't return SQL_SUCCESS, then your error handling should use SQLGetDiagRec() to get the details of the warning or error.
Documentation: SQLGetDiagRec

sqlbindparameter not used for all parameters - mysql & C++

I have the following table defined in MySQL
INSERT INTO routemaster_log (`EntryDateTime`,`Entry`,`Message`,`EntryType`) VALUES (?,?,?,?);
CREATE TABLE `routemaster_log` (
`EntryDateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`Entry` varchar(127) NOT NULL,
`Message` int(11) NOT NULL DEFAULT '0',
`EntryType` varchar(20) NOT NULL DEFAULT 'INFORMATION'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
And the following C++ code to write a record to it
void LogEntries::Insert(string_t LogText, string_t LogType, int MessageNumber)
{
SQLHANDLE hEnv;
SQLRETURN retCode;
SQLCHAR* query;
SQLINTEGER textLength = SQL_NTS;
// now set the text to be written to char *
char* logText = from_string_t(LogText);
char* logType = from_string_t(LogType);
std::string SQLQuery("INSERT INTO routemaster_log (`Entry`,`Message`,`EntryType`) VALUES (?,?,?)");
query = (SQLCHAR *)SQLQuery.c_str();
.
.
.
// log Text
retCode = SQLBindParameter(hStmnt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_CHAR, 0, 0,
logText, sizeof(logText), &textLength);
if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) {
std::cout << "SQL Insert failed binding parameters (LogText)" << std::endl;
}
// Message Number
retCode = SQLBindParameter(hStmnt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &MessageNumber, 0, NULL);
if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) {
std::cout << "SQL Insert failed binding parameters (Message Number)" << std::endl;
}
// Log Type
retCode = SQLBindParameter(hStmnt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_CHAR, 0, 0,
logType, sizeof(logType), &textLength);
if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) {
std::cout << "SQL Insert failed binding parameters (LogType)" << std::endl;
}
retCode = SQLExecDirectA(hStmnt, query, SQL_NTS);
if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
{
SQLWCHAR Msg[255], SqlState[6];
SQLINTEGER NativeError;
SQLRETURN ret2;
SQLSMALLINT i, MsgLen;
i = 1;
while ((ret2 = SQLGetDiagRec(SQL_HANDLE_STMT, hStmnt, i, SqlState, &NativeError,
Msg, sizeof(Msg), &MsgLen)) != SQL_NO_DATA) {
std::cout << Msg << std::endl;
i++;
}
std::cout << "SQL Insert failed writing data to database." << std::endl;
}
}
everything is fine until the SQLExecDirectA this fails with the SQLBindParameter not used for all parameters error (retrieved in the following while loop).
I would expect this if the number of Parameters being bound was different to the number of '?' in the query but they are the same.
Anyone got a suggestion as to what is wrong?
There is actually two issues with the code in the question.
a) The Calls to SQLBindParameter go before the call to SQLPrepareA
b) In the Calls to SQLBindParameter the second Parameter gives the position of the parameter
The revised code - which works is as follows;
// log Text
retCode = SQLBindParameter(hStmnt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_CHAR, 0, 0,
logText, sizeof(logText), &textLength);
if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) {
std::cout << "SQL Insert failed binding parameters (LogText)" << std::endl;
}
// Message Number
retCode = SQLBindParameter(hStmnt, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &MsgNumber, 0, NULL);
if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) {
std::cout << "SQL Insert failed binding parameters (Message Number)" << std::endl;
}
// Log Type
retCode = SQLBindParameter(hStmnt, 3, SQL_PARAM_INPUT,
SQL_C_CHAR, SQL_CHAR, 0, 0,
logType, sizeof(logType), &textLength);
if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) {
std::cout << "SQL Insert failed binding parameters (LogType)" << std::endl;
}
retCode = SQLPrepareA(hStmnt, query, SQL_NTS);
if (retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO) {
std::cout << "SQL Insert failed preparing statement" << std::endl;
}
retCode = SQLExecDirectA(hStmnt, query, SQL_NTS);

SQL Connection with C++ error fetching

So, I got a simple connection to SQL Server, it connects fine, and execute sql fine too, it returns me the first row, but than when it hit the Fetch again it throws this error:
Unhandled exception at 0x011219A0 in JangadaServer.exe: 0xC0000005: Access violation reading location 0x00000008.
code:
bool database::connect()
{
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlenvhandle))
return false;
if (SQL_SUCCESS != SQLSetEnvAttr(sqlenvhandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0))
return false;
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_DBC, sqlenvhandle, &sqlconnectionhandle))
return false;
SQLWCHAR retconstring[1024];
switch (SQLDriverConnect(sqlconnectionhandle,
NULL,
(SQLWCHAR*)TEXT("DRIVER=SQL Server;SERVER=.\\SQLEXPRESS;DATABASE=jangadares;UID=sa;PWD=******;Trusted_Connection=no;"),
SQL_NTS,
retconstring,
1024,
NULL,
SQL_DRIVER_NOPROMPT)){
case SQL_SUCCESS_WITH_INFO:
show_error(SQL_HANDLE_DBC, sqlconnectionhandle);
break;
case SQL_INVALID_HANDLE:
case SQL_ERROR:
show_error(SQL_HANDLE_DBC, sqlconnectionhandle);
return false;
default:
break;
}
return true;
}
bool database::verify_account(char* account, char* password)
{
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_STMT, sqlconnectionhandle, &sqlstatementhandle))
return false;
if (SQL_SUCCESS != SQLExecDirect(sqlstatementhandle, (SQLWCHAR*)TEXT("select * from accounts"), SQL_NTS)){
show_error(SQL_HANDLE_STMT, sqlstatementhandle);
return false;
}
else{
char account[50];
char password[50];
int id;
while (SQLFetch(sqlstatementhandle) == SQL_SUCCESS){
SQLGetData(sqlstatementhandle, 1, SQL_C_UBIGINT, &id, 0, NULL);
SQLGetData(sqlstatementhandle, 2, SQL_C_CHAR, account, 50, NULL);
SQLGetData(sqlstatementhandle, 3, SQL_C_CHAR, password, 50, NULL);
std::string acc = account;
acc.erase(remove_if(acc.begin(), acc.end(), isspace), acc.end());
std::string pwd = password;
pwd.erase(remove_if(pwd.begin(), pwd.end(), isspace), pwd.end());
printf("%d", id);
printf(acc.c_str());
printf(pwd.c_str());
}
}
return false;
}
I don't know what to do, since it returns the first row okay, and it only got one row, so I guess I should handle these error or what?

SQL Statement in C using a variable in query

I am building a C++ program that accesss an SQL database. I am able to connect and return values for the following statment:
retcode = SQLExecDirect(hstmt, (SQLWCHAR*)L"SELECT Beta FROM Equity WHERE Ticker = 'AAPL'", SQL_NTS);
However, I would like to be able to replace 'AAPL' with the string 'ticker', which can be defined using cin>>.
Is there any way to do this?
Thanks for the help, the entire code is below:
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>
#include <string>
using namespace std;
int main(){
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
SQLWCHAR OutConnStr[255];
SQLSMALLINT OutConnStrLen;
// Allocate environment handle
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
// Set the ODBC version environment attribute
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
// Allocate connection handle
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
// Set login timeout to 5 seconds
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
// Connect to data source
retcode = SQLDriverConnect(
hdbc,
0,
(SQLWCHAR*)L"DSN=Phoenix;SERVER=XXX;UID=XXX;PWD=XXX;DRIVER=MySQL Server;",
_countof(L"DSN=Phoenix;SERVER=XXX;UID=XXX;PWD=XXX;DRIVER=MySQL Server;"),
OutConnStr,
255,
&OutConnStrLen,
SQL_DRIVER_COMPLETE );
// Allocate statement handle
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
// Process data
string ticker;
cout << " Enter Ticker: "; //Prompt Ticker
cin >> ticker; //Stores Ticker
//retcode = SQLExecDirect(hstmt, (SQLWCHAR*)L"SELECT Beta FROM Equity WHERE Ticker = 'AAPL'", SQL_NTS);
retcode = SQLExecDirect(hstmt, (SQLWCHAR*)L"SELECT Beta FROM Equity WHERE Ticker = ticker", SQL_NTS);
if (retcode == SQL_SUCCESS) {
SQLINTEGER cbTestStr, iCount = 1;
SQLFLOAT dTestFloat;
SQLCHAR beta[200];
while (TRUE) {
retcode = SQLFetch(hstmt);
if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) {
cout<<"An error occurred";
}
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){
SQLGetData(hstmt, 1, SQL_C_CHAR, beta, 200, &cbTestStr);
/* Print the row of data */
cout<<"Beta for "<< ticker << " = " << beta <<endl;
double bi;
cin >> bi;
} else {
break;
}
}
}else{
cout<<"Query execution error."<<endl;
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
}else{
cout<<"Connection error"<<endl;
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
system("pause");
return 0;
}
Have you tried something like after your cin >> ticker; line.
string sql;
sql = "SELECT Beta FROM Equity WHERE Ticker='";
strcat (sql,ticker);
strcat (sql, "'");
Then use the sql string in SQLExecDirect line
Replace the statement text with sql.
Sorry my c syntax is rusty. The point is to retrieve ticker value and concatenate that to the sql string while surrounding the input (ticker) with single quotes. Then use this as your execution statement.
Hope it works.

ODBC write blob example Oracle C++

Could you give me an example in c++ of inserting a blob in an Oracle database using ODBC API? It's my first time working with BLOB type so it is abstract to me. I have researched the Internet a lot and now it is all messy in my head. An example would really help me.
I have a short(ish) example in C. The basic principle to insert blobs via ODBC is this:
SQLPrepare("insert into mytable (mycolumne) values(?)");
SQLBindParameter(1, other_args, indicator SQL_LEN_DATA_AT_EXEC(size));
SQLExecute will return SQL_NEED_DATA
call SQLParamData to find which parameter data is required for
call SQLPutData as much as you like in chunks to insert data
call SQLParamData again to find the next parameter requiring data
In example code here you'll have to write your own do_a_error() function but it just calls SQLGetDiagRec.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined (WIN32)
# include <windows.h>
# include <io.h>
#else
# include <unistd.h>
#endif
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
#include "helper.h" /* contained do_a_error() defn etc - you won't have this header */
#ifdef WIN32
# define F_OK 0
# define W_OK 2
# define R_OK 4
# define access _access /* file check */
#endif
static SQLUINTEGER array_row_counts;
static SQLUINTEGER array_selects;
static SQLUINTEGER static_ca1;
static SQLUINTEGER static_ca2;
unsigned int debug=0;
const char fixed_data_source[] = "example";
#define TEST_FILE "easycd.jpg"
#define DISPLAY_GIF "/usr/X11/bin/xv"
static short insert_into_table(
SQLHDBC *hdbc,
typeinfo_t typeinfo);
/************************************************************************/
/* */
/* main */
/* ==== */
/* */
/************************************************************************/
int main(int argc, char *argv[], char *envp[])
{
SQLHENV henv; /* environment handle */
SQLHDBC hdbc; /* database handle */
char *data_source_name; /* chosen datasource */
SQLRETURN ret; /* function return status */
char in_connection_string[512]; /* SQLDriverConnect string */
char out_connection_string[512]; /* returned connection string */
SQLSMALLINT out_connection_string_len; /* ... and length */
unsigned int i; /* loop variable */
typeinfo_t typeinfo[100]; /* data type information */
int type_element = -1;
SQLINTEGER max_column_size = 0; /* largest column */
/*
* Get the datasource name.
*/
if (argc > 1)
{
for (i = 1; i < argc; i++)
{
if (!strcmp (argv[i], "-d")) debug = 1;
}
if (((argc > 2) && debug) ||
((argc > 1) && !debug))
data_source_name = argv[argc - 1];
}
else
{
data_source_name = fixed_data_source;
}
sprintf(in_connection_string, "DSN=%s;", data_source_name);
/*
* Allocate and set up the environment and connection.
*/
if (SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv) != SQL_SUCCESS)
{
fprintf(stderr, "** Failed to allocate environment **\n");
exit(1);
}
if (SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC3, 0) != SQL_SUCCESS)
{
do_a_error(SQL_HANDLE_ENV, henv, "SQLSetEnvAttr");
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(2);
}
if (SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) != SQL_SUCCESS)
{
do_a_error(SQL_HANDLE_ENV, henv, "SQLAllocHandle");
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(3);
}
ret = SQLDriverConnect(hdbc, NULL,
(SQLCHAR *)in_connection_string, SQL_NTS,
(SQLCHAR *)out_connection_string,
sizeof(out_connection_string),
&out_connection_string_len, SQL_DRIVER_COMPLETE);
if (!SQL_SUCCEEDED(ret))
{
do_a_error(SQL_HANDLE_DBC, hdbc, "SQLDriverConnect");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(4);
}
if (out_connection_string_len > sizeof(out_connection_string))
{
out_connection_string[sizeof(out_connection_string) - 1] = '\0';
}
else
{
out_connection_string[out_connection_string_len] ='\0';
}
printf("%s\n", out_connection_string);
if (ret == SQL_SUCCESS_WITH_INFO)
{
do_a_error(SQL_HANDLE_DBC, hdbc, "SQLDriverConnect");
}
/*
* Get a list of the types supported.
*/
memset(typeinfo, '\0', sizeof(typeinfo));
do_get_info(hdbc, &array_row_counts, &array_selects,
&static_ca1, &static_ca2);
if (!SQL_SUCCEEDED(do_type_info(hdbc, typeinfo)))
{
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(5);
}
/*
* Find a type big enough for our gif image.
*/
for (i = 0; strlen(typeinfo[i].type_name); i++)
{
if ((typeinfo[i].column_size > max_column_size) &&
(max_column_size != SQL_NO_TOTAL))
{
max_column_size = typeinfo[i].column_size;
type_element = i;
}
else
{
if (typeinfo[i].column_size == SQL_NO_TOTAL)
{
if (max_column_size != SQL_NO_TOTAL)
{
max_column_size = SQL_NO_TOTAL;
type_element = i;
}
}
}
}
if (type_element < 0) abort();
if (debug)
printf("\t Biggest type is %s at %ld in size, requiring \"%s\"\n",
typeinfo[type_element].type_name,
typeinfo[type_element].column_size,
typeinfo[type_element].create_params);
/*
* Delete existing table and create a new one.
*/
ret = do_create_table(hdbc, "\"blob\"", CREATE_TABLE_BIGCOL,
typeinfo[type_element].column_size,
typeinfo[type_element].type_name,
typeinfo[type_element].create_params);
if (!SQL_SUCCEEDED(ret))
{
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(4);
}
insert_into_table(hdbc, typeinfo[type_element]);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
/************************************************************************/
/* */
/* insert_into_table */
/* ================= */
/* */
/************************************************************************/
static short insert_into_table(
SQLHDBC *hdbc,
typeinfo_t typeinfo)
{
SQLINTEGER len_ind[2]; /* parameter lengths */
SQLINTEGER p1; /* first parameter array */
SQLCHAR p2[50000]; /* second parameter array */
SQLINTEGER row_counts; /* rows affected */
SQLRETURN ret; /* function status return */
unsigned int row; /* current row */
SQLHSTMT hstmt; /* statement handle */
char qbuf[1024]; /* query buffer */
FILE *fp; /* test file file ptr */
size_t readb; /* bytes read from test file */
size_t writeb; /* bytes written to test file */
SQLINTEGER retrieved; /* data retrieved from GetData */
unsigned int pos; /* position in GetData buffer */
printf("---------- insert_into_table ----------\n");
printf("-- Creating rows with BIG column data --\n");
if (access(TEST_FILE, R_OK))
{
fprintf(stderr, "Can't find test binary %s\n", TEST_FILE);
return SQL_ERROR;
}
if (!(fp = fopen(TEST_FILE, "rb")))
{
fprintf(stderr, "Failed to open %s for reading\n", TEST_FILE);
return SQL_ERROR;
}
clearerr(fp);
readb = fread(p2, 1, sizeof(p2), fp);
if ((readb == 0) || ferror(fp))
{
fprintf(stderr, "Failed to read data from %s\n", TEST_FILE);
return SQL_ERROR;
}
if (readb >= sizeof(p2))
{
fprintf(stderr, "%s is too big a file\n", TEST_FILE);
return SQL_ERROR;
}
fclose(fp);
if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) != SQL_SUCCESS)
{
do_a_error(SQL_HANDLE_DBC, hdbc, "SQLAllocHandle");
return SQL_ERROR;
}
/*
* Delete all the rows.
*/
sprintf(qbuf, "delete from \"blob\"");
printf("\"%s\"\n", qbuf);
ret = SQLExecDirect(hstmt, (SQLCHAR *)qbuf, SQL_NTS);
if (ret != SQL_SUCCESS)
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLExecDirect");
/*
* Create the rows.
*/
sprintf(qbuf, "insert into \"blob\" (a,b) values(?,?)");
printf("\"%s\"\n", qbuf);
if (SQLPrepare(hstmt, (SQLCHAR *)qbuf, SQL_NTS) != SQL_SUCCESS)
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLPrepare");
return SQL_ERROR;
}
/*
* Bind Parameters
*/
ret = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
5, 0, &p1, 0, &len_ind[0]);
if (!SQL_SUCCEEDED(ret))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLBindParameter");
return ret;
}
ret = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_BINARY,
typeinfo.sql_data_type,
sizeof(p2), 0, (SQLPOINTER)2, 0,
&len_ind[1]);
if (!SQL_SUCCEEDED(ret))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLBindParameter");
return ret;
}
printf("\tInserting rows into table\n");
for (row = 0; row < 1; row++)
{
/* a */
p1 = row;
len_ind[0] = sizeof(p1);
/* b */
len_ind[1] = SQL_LEN_DATA_AT_EXEC(readb);
ret = SQLExecute(hstmt);
if (ret == SQL_NEED_DATA)
{
SQLPOINTER val;
ret = SQLParamData(hstmt, &val);
if (ret != SQL_NEED_DATA)
{
fprintf(stderr,
"** SQLParamData returned %d, "
"expected SQL_NEED_DATA **\n", ret);
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLParamData");
return SQL_ERROR;
}
if (val != (SQLPOINTER)2)
{
fprintf(stderr,
"** SQLParamData said it required data for parameter "
"marker %p, and we expected 2 **\n", val);
return SQL_ERROR;
}
ret = SQLPutData(hstmt, p2, readb);
if (!SQL_SUCCEEDED(ret))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLPutData");
return SQL_ERROR;
}
ret = SQLParamData(hstmt, &val);
if (!SQL_SUCCEEDED(ret))
{
fprintf(stderr,
"** Second SQLParamData returned %d, "
"We though all data was sent **\n", ret);
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLParamData");
return SQL_ERROR;
}
}
else if (!SQL_SUCCEEDED(ret))
{
fprintf(stderr,
"** Driver returned a successful state for SQLExecute "
"buf there were data-at-exec parameters **\n");
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLExecute");
return SQL_ERROR;
}
else
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLExecute");
}
if (!SQL_SUCCEEDED(SQLRowCount(hstmt, &row_counts)))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLRowCount");
}
if (row_counts != 1)
{
fprintf(stderr, "** RowCount=%ld, expected 1 **\n", row_counts);
}
printf(".");
fflush(stdout);
}
printf("\n");
/*
* Now get it back to check we sent it OK.
*/
memset(p2, '\0', sizeof(p2));
sprintf(qbuf, "select * from \"blob\"");
if (!SQL_SUCCEEDED(ret = SQLPrepare(hstmt, (SQLCHAR *)qbuf, SQL_NTS)))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLPrepare");
return SQL_ERROR;
}
if (!SQL_SUCCEEDED(ret = SQLExecute(hstmt)))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLExecute");
}
if (!SQL_SUCCEEDED(ret = SQLFetch(hstmt)))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLFetch");
}
pos = 0;
while(SQL_SUCCEEDED(ret = SQLGetData(hstmt, 2, SQL_C_BINARY,
&p2[pos], sizeof(p2), &retrieved)))
{
if (retrieved == SQL_NO_TOTAL) abort();
if (retrieved == SQL_NULL_DATA) abort();
pos += retrieved;
}
if (ret != SQL_NO_DATA)
{
fprintf(stderr,
"** SQLGetData finished with a status other than SQL_NO_DATA **\n");
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLGetData");
return SQL_ERROR;
}
if (!SQL_SUCCEEDED(SQLCloseCursor(hstmt)))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLCloseCursor");
}
if (!(fp = fopen("out.jpg", "w")))
{
fprintf(stderr, "** Failed to open out.jpg for writing **\n");
return SQL_ERROR;
}
writeb = fwrite(p2, 1, pos, fp);
if (writeb != pos)
{
fprintf(stderr, "** Failed to write out.jpg **\n");
return SQL_ERROR;
}
fclose(fp);
system(DISPLAY_GIF" out.jpg");
printf("\tResetting parameters\n");
if (!SQL_SUCCEEDED(SQLFreeStmt(hstmt, SQL_RESET_PARAMS)))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLFreeStmt");
}
printf("\tClosing statement\n");
if (!SQL_SUCCEEDED(SQLFreeStmt(hstmt, SQL_CLOSE)))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLFreeStmt");
}
printf("\tDropping Statement\n");
ret = SQLFreeStmt(hstmt, SQL_DROP);
if (!SQL_SUCCEEDED(ret))
{
do_a_error(SQL_HANDLE_STMT, hstmt, "SQLFreeStmt");
}
return ret;
}