SQLSTATE 24000 - Invalid cursor state ODBC VS c++ - c++

I've got a fairly simple c++ application that uses ODBC to connect to a SQL Server instance that uses a stored procedure to populate.
I use the lines of a wstring object to build a query that is then passed through to the stored procedure. Everything works fine if I run it a single time - however, I want to be able to loop through a quite extensive amount of code (3000+ excel rows) and as I do it the cursor error mentioned in the title occurs.
This is the stored procedure:
GO
CREATE PROCEDURE s_addHistorical
#Symbol nchar(10),#Date datetime,
#Open decimal(8,2),#Close decimal(8,2),#MinPrice decimal(8,2),
#MaxPrice decimal(8,2),#Volume int
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
MERGE HistoricalStock WITH (UPDLOCK) AS myTarget
USING (SELECT #Symbol AS Symbol,
#Date AS Date, #Open AS [Open], #Close AS [Close],
#MinPrice AS MinPrice, #MaxPrice AS MaxPrice,#Volume AS Volume) AS mySource
ON mySource.Symbol = myTarget.Symbol AND mySource.Date = myTarget.Date
WHEN MATCHED
THEN UPDATE
SET [Open] = mySource.[Open], [Close] = mySource.[Close],
MinPrice = mySource.MinPrice, MaxPrice = mySource.MaxPrice, Volume = mySource.Volume
WHEN NOT MATCHED
THEN
INSERT(Symbol,Date,[Open],[Close],MinPrice,MaxPrice,Volume)
VALUES(#Symbol,#Date,#Open,#Close,#MinPrice,#MaxPrice,#Volume);
COMMIT
GO
And this is the connector:
#include "stdafx.h"
#include "database_con.h"
////////////////////////////////////////////////////////////////////////
// Show errors from the SQLHANDLE
void database_con::show_error(unsigned int handletype, const SQLHANDLE& handle)
{
SQLWCHAR sqlstate[1024];
SQLWCHAR message[1024];
if (SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message, 1024, NULL))
wcout << "Message: " << message << "\nSQLSTATE: " << sqlstate << endl;
}
////////////////////////////////////////////////////////////////////////
// Builds the stored procedure query.
std::wstring database_con::buildQuery(vector<std::wstring> input)
{
std::cout << "Building the query" << std::endl;
std::wstringstream builder;
builder << L"EXEC sp_addHistorical " << "#Symbol='" << L"" << input.at(0) << "'," <<
"#Date=" << (wstring)L"" << input.at(1) << "," <<
"#Open=" << (wstring)L"" << input.at(2) << "," <<
"#Close=" << (wstring)L"" << input.at(3) << "," <<
"#MaxPrice=" << (wstring)L"" << input.at(4) << "," <<
"#MinPrice=" << (wstring)L"" << input.at(5) << "," <<
"#Volume=" << (wstring)L"" << input.at(6) << ";";
return builder.str();
}
////////////////////////////////////////////////////////////////////////
// Adds a substring of the string before the delimiter to a vector<wstring> that is returned.
std::vector<wstring> database_con::parseData(wstring line, char delim) {
size_t pos = 0;
std::vector<std::wstring> vOut;
while ((pos = line.find(delim)) != std::string::npos) {
vOut.push_back(line.substr(0, pos));
line.erase(0, pos + 2);
}
vOut.push_back(line.substr(0, pos));
return vOut;
}
std::wstring database_con::StringToWString(const std::string& s)
{
std::wstring temp(s.length(), L' ');
std::copy(s.begin(), s.end(), temp.begin());
return temp;
}
database_con::database_con(std::string historical){
/*
Set up the handlers
*/
/* Allocate an environment handle */
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
/* We want ODBC 3 support */
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
/* Allocate a connection handle */
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
/* Connect to the DSN */
SQLDriverConnectW(dbc, NULL, L"DRIVER={SQL Server};SERVER=ERA-PC-STUART\\JBK_DB;DATABASE=master;UID=geo;PWD=kalle123;", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
/* Check for success */
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt))
{
show_error(SQL_HANDLE_DBC, dbc);
std::cout << "Failed to connect";
}
std::wstringstream stream(StringToWString(historical));
std::wstring line;
while (std::getline(stream, line)) {
vector<wstring> vHistorical = parseData(L"" + line, ',');
std::wstring SQL = buildQuery(vHistorical);
if (SQL_SUCCESS != SQLExecDirectW(stmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS)) {
show_error(SQL_HANDLE_STMT, stmt);
}
}
}
database_con::~database_con() {
}
I've been looking around at google and on SO, but I can't seem to find any questions that are usable in my current question. Most of them seem to be revolving around stored procedures sending back some sort of extracts, whereas my SP is simply inserting / updating.
Any sort of help would be greatly appriciated. :)
Anyone?

You need to call SQLCloseCursor to release the Cursor.
Change your code to:
while (std::getline(stream, line)) {
vector<wstring> vHistorical = parseData(L"" + line, ',');
std::wstring SQL = buildQuery(vHistorical);
if (SQL_SUCCESS != SQLExecDirectW(stmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS)) {
show_error(SQL_HANDLE_STMT, stmt);
}
// Close Cursor before next iteration starts:
SQLRETURN closeCursRet = SQLCLoseCursor(stmt);
if(!SQL_SUCCEEDED(closeCursRet))
{
// maybe add some handling for the case that closing failed.
}
}
See: https://msdn.microsoft.com/en-us/library/ms709301%28v=vs.85%29.aspx

Related

nesting function calls in c++ thread

I've got a threading problem that I've been trying to find an answer to on SO and Google, but with no luck.
Simply put I would want to create a thread that can execute a function that is using another function as a parameter (with its own arguments - see below).
I've followed these guides (https://www.justsoftwaresolutions.co.uk/threading/multithreading-in-c++0x-part-2-function-objects-and-arguments.html) on threading that work absolutely flawlessly, except for the above mentioned use case.
This is the specific line where I attempt to create the thread:
std::thread t(executeQuery, buildQuery(*_mVecHistIter, symbol));
And these are the nested functions definitions:
std::wstring database_con::buildQuery(vector<std::wstring> input, string symbol)
void database_con::executeQuery(wstring query)
And the error:
no instance of constructor "std::thread::thread" matches the argument
list
I could simply rebuild the functions so that buildQuery starts executeQuery. But I would want to separate the calls and ensure that as much as possible is done from the class "body" for readability and maintainability down the line.
Any kind of advice, pointers or ideas of where I can find more material on the subject would be appreciated! :)
I'm using MSVC 2015.
Edit:
#include "stdafx.h"
#include "database_con.h"
////////////////////////////////////////////////////////////////////////
// Show errors from the SQLHANDLE
void database_con::show_error(unsigned int handletype, const SQLHANDLE& handle)
{
SQLWCHAR sqlstate[1024];
SQLWCHAR message[1024];
if (SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message, 1024, NULL))
wcout << "Message: " << message << "\nSQLSTATE: " << sqlstate << endl;
}
std::wstring database_con::StringToWString(const std::string& s)
{
std::wstring temp(s.length(), L' ');
std::copy(s.begin(), s.end(), temp.begin());
return temp;
}
////////////////////////////////////////////////////////////////////////
// Builds the stored procedure query.
std::wstring database_con::buildQuery(vector<std::wstring> input, string symbol)
{
std::wstringstream builder;
builder << L"EXEC sp_addHistorical " << "#Symbol='" << L"" << StringToWString(symbol) << "'," <<
"#Date='" << (wstring)L"" << input.at(0) << "'," <<
"#Open=" << (wstring)L"" << input.at(1) << "," <<
"#Close=" << (wstring)L"" << input.at(2) << "," <<
"#MaxPrice=" << (wstring)L"" << input.at(3) << "," <<
"#MinPrice=" << (wstring)L"" << input.at(4) << "," <<
"#Volume=" << (wstring)L"" << input.at(5) << ";";
return builder.str();
}
void database_con::executeQuery(wstring query) {
if (SQL_SUCCESS != SQLExecDirectW(stmt, const_cast<SQLWCHAR*>(query.c_str()), SQL_NTS)) {
std::cout << "Execute error " << std::endl;
show_error(SQL_HANDLE_STMT, stmt);
std::wcout << L"Unsuccessful Query: " << query << std::endl;
}
// Close Cursor before next iteration starts:
SQLRETURN closeCursRet = SQLFreeStmt(stmt, SQL_CLOSE);
if (!SQL_SUCCEEDED(closeCursRet))
{
show_error(SQL_HANDLE_STMT, stmt);
// maybe add some handling for the case that closing failed.
}
}
////////////////////////////////////////////////////////////////////////
// Constructs a database connector object with the historical data and its symbol
database_con::database_con(std::vector<std::vector<std::wstring>> historical, string symbol){
/*
Set up the handlers
*/
/* Allocate an environment handle */
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
/* We want ODBC 3 support */
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
/* Allocate a connection handle */
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
/* Connect to the DSN */
SQLDriverConnectW(dbc, NULL, L"DRIVER={SQL Server};SERVER=ERA-PC-STUART\\JBK_DB;DATABASE=master;UID=geo;PWD=kalle123;", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
/* Check for success */
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt))
{
show_error(SQL_HANDLE_DBC, dbc);
std::cout << "Failed to connect";
}
std::cout << "Building and executing the query" << std::endl;
for (_mVecHistIter = historical.begin();
_mVecHistIter != historical.end();
_mVecHistIter+5) {
std::thread t(&database_con::executeQuery, *this, buildQuery(*_mVecHistIter, symbol));
std::thread t2(&database_con::executeQuery, *this, buildQuery(*_mVecHistIter, symbol));
std::thread t3(&database_con::executeQuery, *this, buildQuery(*_mVecHistIter, symbol));
std::thread t4(&database_con::executeQuery, *this, buildQuery(*_mVecHistIter, symbol));
std::thread t5(&database_con::executeQuery, *this, buildQuery(*_mVecHistIter, symbol));
t.join();
t2.join();
t3.join();
t4.join();
t5.join();
//executeQuery(buildQuery(*_mVecHistIter, symbol));
}
/*_mSymbol = symbol;
std::wstringstream stream(StringToWString(historical));
std::wstring line;
int row = 0;
while (std::getline(stream, line)) {
if (row > 0) {
vector<wstring> vHistorical = parseData(L"" + line, ',');
std::wstring SQL = buildQuery(vHistorical, _mSymbol);
if (SQL_SUCCESS != SQLExecDirectW(stmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS)) {
std::cout << "Execute error " << std::endl;
show_error(SQL_HANDLE_STMT, stmt);
std::wcout << L"Unsuccessful Query: " << SQL << std::endl;
}
// Close Cursor before next iteration starts:
SQLRETURN closeCursRet = SQLFreeStmt(stmt, SQL_CLOSE);
if (!SQL_SUCCEEDED(closeCursRet))
{
show_error(SQL_HANDLE_STMT, stmt);
// maybe add some handling for the case that closing failed.
}
}
row++;
}*/
std::cout << "Query " << _mSymbol << " ready" << std::endl;
}
database_con::~database_con() {
std::cout << "The database object has been deleted" << std::endl;
}
OK, I probably misunderstood the question. You don't want create a thread using a function, having one of its arguments another function. But rather create a thread using a function and having its parameter computed by another function. There is nothing particular about that. You probably just forget to add & operator to take an address of the function.
std::thread t(&executeQuery, buildQuery(*_mVecHistIter, symbol));
^-- note the &
EDIT
So, you forget to mention that database_con is a class. In order to use class member function as param for function acception pointer to function as parameter (in your case std::thread::thread) you have to use fully qualified name with operand & (&database_con::executeQuery). However, since that is non static member function, it will require its first argument pointer to instance of such object (google std::thread non-static member function).
std::thread t(&database_con::executeQuery, this, buildQuery(*_mVecHistIter, symbol));
Previous answer
Did you considered using std::function?
#include <functional>
#include <thread>
int foo(int arg1, int arg2)
{
return arg1 + arg2;
}
void bar(std::function<int(int, int)> fnc, int arg1, int arg2)
{
fnc(arg1, arg2);
}
int main()
{
std::thread thr{&bar, &foo, 1, 2};
}

Finding SQL server deadlock cause

I have a simple c++ program running on MSVC using an ODBC connection to execute a stored procedure.
When running it on the main thread it works fine, but when I attempt to multithread the same class I am getting this error:
(Process ID XX) was deadlocked on lock resource....
As mentioned above I can run it fine on the main thread and also on two threads with no issues.
This is how I spawn, use and join the threads:
historical apple("AAPL");
historical google("GOOG");
historical yahoo("YHOO");
historical samsung("005930.KS");
historical ibm("IBM");
auto t1 = thread([&] {apple.go(); });
auto t2 = thread([&] {google.go(); });
auto t3 = thread([&] {yahoo.go(); });
auto t4 = thread([&] {samsung.go(); });
auto t5 = thread([&] {ibm.go(); });
//writer(his.getHistorical()); // this writes to the file test.csv
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
I know it looks like shit, but I'm basically trying to see how hard I can push the software before making it look nice and more formatted.
This is how I call the stored procedure:
#include "stdafx.h"
#include "database_con.h"
////////////////////////////////////////////////////////////////////////
// Show errors from the SQLHANDLE
void database_con::show_error(unsigned int handletype, const SQLHANDLE& handle)
{
SQLWCHAR sqlstate[1024];
SQLWCHAR message[1024];
if (SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message, 1024, NULL))
wcout << "Message: " << message << "\nSQLSTATE: " << sqlstate << endl;
}
////////////////////////////////////////////////////////////////////////
// Builds the stored procedure query.
std::wstring database_con::buildQuery(vector<std::wstring> input, string symbol)
{
std::wstringstream builder;
builder << L"EXEC sp_addHistorical " << "#Symbol='" << L"" << StringToWString(symbol) << "'," <<
"#Date='" << (wstring)L"" << input.at(0) << "'," <<
"#Open=" << (wstring)L"" << input.at(1) << "," <<
"#Close=" << (wstring)L"" << input.at(2) << "," <<
"#MaxPrice=" << (wstring)L"" << input.at(3) << "," <<
"#MinPrice=" << (wstring)L"" << input.at(4) << "," <<
"#Volume=" << (wstring)L"" << input.at(5) << ";";
return builder.str();
}
////////////////////////////////////////////////////////////////////////
// Adds a substring of the string before the delimiter to a vector<wstring> that is returned.
std::vector<wstring> database_con::parseData(wstring line, char delim) {
size_t pos = 0;
std::vector<std::wstring> vOut;
while ((pos = line.find(delim)) != std::string::npos) {
vOut.push_back(line.substr(0, pos));
line.erase(0, pos + 1);
}
vOut.push_back(line.substr(0, pos));
return vOut;
}
////////////////////////////////////////////////////////////////////////
// Converts a std::string to a std::wstring
std::wstring database_con::StringToWString(const std::string& s)
{
std::wstring temp(s.length(), L' ');
std::copy(s.begin(), s.end(), temp.begin());
return temp;
}
void database_con::historicalLooper(string historical) {
}
////////////////////////////////////////////////////////////////////////
// Constructs a database connector object with the historical data and its symbol
database_con::database_con(std::string historical, string symbol){
/*
Set up the handlers
*/
/* Allocate an environment handle */
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
/* We want ODBC 3 support */
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
/* Allocate a connection handle */
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
/* Connect to the DSN */
SQLDriverConnectW(dbc, NULL, L"DRIVER={SQL Server};SERVER=ERA-PC-STUART\\JBK_DB;DATABASE=master;UID=geo;PWD=kalle123;", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
/* Check for success */
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt))
{
show_error(SQL_HANDLE_DBC, dbc);
std::cout << "Failed to connect";
}
_mSymbol = symbol;
std::wstringstream stream(StringToWString(historical));
std::wstring line;
int row = 0;
while (std::getline(stream, line)) {
if (row > 0) {
vector<wstring> vHistorical = parseData(L"" + line, ',');
std::wstring SQL = buildQuery(vHistorical, _mSymbol);
if (SQL_SUCCESS != SQLExecDirectW(stmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS)) {
std::cout << "Execute error " << std::endl;
show_error(SQL_HANDLE_STMT, stmt);
std::wcout << L"Unsuccessful Query: " << SQL << std::endl;
}
// Close Cursor before next iteration starts:
SQLRETURN closeCursRet = SQLFreeStmt(stmt, SQL_CLOSE);
if (!SQL_SUCCEEDED(closeCursRet))
{
show_error(SQL_HANDLE_STMT, stmt);
// maybe add some handling for the case that closing failed.
}
}
row++;
}
std::cout << "Query " << _mSymbol << " ready" << std::endl;
}
database_con::~database_con() {
}
And finally this is the stored procedure:
GO
CREATE PROCEDURE sp_addHistorical
#Symbol nchar(10),#Date datetime,
#Open decimal(12,2),#Close decimal(12,2),#MinPrice decimal(12,2),
#MaxPrice decimal(12,2),#Volume int
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
MERGE HistoricalStock WITH (UPDLOCK) AS myTarget
USING (SELECT #Symbol AS Symbol,
#Date AS Date, #Open AS [Open], #Close AS [Close],
#MinPrice AS MinPrice, #MaxPrice AS MaxPrice,#Volume AS Volume) AS mySource
ON mySource.Symbol = myTarget.Symbol AND mySource.Date = myTarget.Date
WHEN MATCHED
THEN UPDATE
SET [Open] = mySource.[Open], [Close] = mySource.[Close],
MinPrice = mySource.MinPrice, MaxPrice = mySource.MaxPrice, Volume = mySource.Volume
WHEN NOT MATCHED
THEN
INSERT(Symbol,Date,[Open],[Close],MinPrice,MaxPrice,Volume)
VALUES(#Symbol,#Date,#Open,#Close,#MinPrice,#MaxPrice,#Volume);
COMMIT
GO
Any sort of help or advice on either how it's all structured or pointers to good examples regarding the issue I'm facing would be greatly appreciated.
I'm somewhat new to SQL server (more importantly to stored procedures) and can't really figure out what is wrong, even though I understand what a deadlock is.
Thanks!

sqlite3_exec not commit immediately

Using sqlite3_exec on an embedded system. I require the write to be done asap, so if the power is lost, the data is saved. However I've found the machine must be on for ~10 seconds before the data is fully written! Is there a setting to try and speed it up?
Using journal mode DELETE ("PRAGMA journal_mode=DELETE;), and Synchronous mode FULL ("PRAGMA synchronous=FULL;").
I've tried sending "BEGIN;" and "COMMIT;" before and after the UPDATE, respectively. No change.
std::ostringstream oss;
std::ostringstream oss_err;
oss << "UPDATE " << sTableName << " SET " << pon_rstc_db[LookupParamIndex(param)].column_name << "='" << sValue << "';";
if (!isDatabaseOpen())
OpenDatabase(sDatabaseName);
if (isDatabaseOpen())
{
char* db_err = 0;
int rc;
rc = sqlite3_exec(myDatabase, oss.str().c_str(), NULL, 0, &db_err);
if (rc == SQLITE_OK)
{
bResponse = true;
}
else
{
oss_err << db_err;
oss_err << "Update failed for " << LookUpColumnName(param) << ". Data not saved.";
DisplayError(oss_err.str());
bResponse = false;
}
sqlite3_free(db_err);
db_err = 0;
}
else
{
DisplayError("executing statement while database closed");
}

Troubleshooting SQL Server connection in C++ using Visual Studio Express 2013

I've been trying to get a simple program together that can perform some simple operations on a SQL Server database, but can't get any of the tutorials to actually run. I'm trying to figure out if the problem is with the code or with my ODBC settings. Any help/insight is greatly appreciated.
EDIT/UPDATE: ADDITIONAL DETAIL & CODE BELOW
The main program right now is based on this tutorial. I had to make a few changes so that VS Express 2013 would compile the code:
All instances of SQLCHAR * had to be changed to SQLWCHAR *.Had to use wcout to output the error messagesThe 'GOTO: FINISHED' used in the tutorial generated errors that the objects might be uninitialized. I added an 'UNFIN' block after 'FINISHED' and changed those generating errors to GOTO UNFIN to make the compier happyAdded a few debugging markers to make sure I was following the program properlyChanged the connection string to match the server, username and password of the database I'm trying to connect to. Note: Target database uses SQLServer2008
On running the program, I get the following error message (generated by the show_error() function):
Messsage: [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified
nSQLSTATE: IM002
Could it be something as simple as an ODBC setting that I need to toggle on my machine or a dependency I've missed in the project setup?
Here's the code. (Note that there are extra headers for other features being tested. Said other features are commented out in my current test program and deleted from the below copy-paste to reduce confusion)
#include "stdafx.h"
#include <stdio.h>
#include <string>
#include <sstream>//Used to int to string, and string to int operations
#include <stdlib.h>
#include <fstream>//Used for file opening, appending and writing operations
#include <iostream>
#include <Windows.h>//Used for sleep command, and window "clearwindow" function
#include <sqlext.h> // Used for writing to SQL database
#include <sqltypes.h>
#include <sql.h>
using namespace std;
void show_error(unsigned int handletype, const SQLHANDLE& handle){
SQLWCHAR sqlstate[1024];
SQLWCHAR message[1024];
cout << "In show_error" << endl;
if (SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message, 1024, NULL)){
cout << "Message: ";
wcout << message;
cout << endl << "nSQLSTATE: ";
wcout << sqlstate;
cout << endl;
}
}
bool write_to_database(/*string dbconnection, string fields, string values*/){
SQLHANDLE sqlenvhandle;
SQLHANDLE sqlconnectionhandle;
SQLHANDLE sqlstatementhandle;
SQLRETURN retcode;
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlenvhandle))
goto UNFIN;
if (SQL_SUCCESS != SQLSetEnvAttr(sqlenvhandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0))
goto UNFIN;
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_DBC, sqlenvhandle, &sqlconnectionhandle))
goto UNFIN;
SQLWCHAR retconstring[1024];
cout << "Made it this far at least" << endl;
switch (SQLDriverConnect(sqlconnectionhandle,
NULL,
(SQLWCHAR*)"DRIVER={SQL Server};SERVER=sqlserver.myhost.com, 1433;DATABASE=MyDatabase;UID=xxxxx;PWD=xxxxx",
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:
cout << "Now we're in SQL_ERROR" << endl;
show_error(SQL_HANDLE_DBC, sqlconnectionhandle);
goto FINISHED;
default:
break;
}
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_STMT, sqlconnectionhandle, &sqlstatementhandle))
goto FINISHED;
if (SQL_SUCCESS != SQLExecDirect(sqlstatementhandle, (SQLWCHAR*)"select * from testtable", SQL_NTS)){
show_error(SQL_HANDLE_STMT, sqlstatementhandle);
goto FINISHED;
}
else{
char name[64];
char address[64];
int id;
while (SQLFetch(sqlstatementhandle) == SQL_SUCCESS){
SQLGetData(sqlstatementhandle, 1, SQL_C_ULONG, &id, 0, NULL);
SQLGetData(sqlstatementhandle, 2, SQL_C_CHAR, name, 64, NULL);
SQLGetData(sqlstatementhandle, 3, SQL_C_CHAR, address, 64, NULL);
cout << id << " " << name << " " << address << endl;
}
}
FINISHED:
SQLFreeHandle(SQL_HANDLE_STMT, sqlstatementhandle);
SQLDisconnect(sqlconnectionhandle);
SQLFreeHandle(SQL_HANDLE_DBC, sqlconnectionhandle);
SQLFreeHandle(SQL_HANDLE_ENV, sqlenvhandle);
goto ALLOVER;
UNFIN:
cout << "Everything is unfinished" << endl;
ALLOVER:
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
write_to_database();
return 0;
}
EDIT/UPDATE:
Continuing to try and figure out where the error is. Using code based off the tutorial at EasySoft to get the list of DSN available feels a little bit like progress. Here's the updated program and result:
// SQLTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <string>
#include <iostream>
#include <Windows.h>//Used for sleep command, and window "clearwindow" function
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h> // Used for writing to SQL database
using namespace std;
static void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT handletype){
SQLWCHAR sqlstate[1024];
SQLWCHAR message[1024];
if (SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message, 1024, NULL)){
cout << "Message: ";
wcout << message;
cout << " nSQLSTATE: ";
wcout << sqlstate;
cout << endl;
}
}
static void do_sql(){
SQLHENV env;
SQLWCHAR dsn[256];
SQLWCHAR desc[256];
SQLSMALLINT dsn_ret;
SQLSMALLINT desc_ret;
SQLUSMALLINT direction;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
direction = SQL_FETCH_FIRST;
cout << "SQL DATA SOURCES:" << endl;
while (SQL_SUCCEEDED(ret = SQLDataSources(env, direction,
dsn, sizeof(dsn), &dsn_ret,
desc, sizeof(desc), &desc_ret))) {
direction = SQL_FETCH_NEXT;
wcout << dsn << " | " << desc << endl;
if (ret == SQL_SUCCESS_WITH_INFO) printf("\tdata truncation\n");
}
SQLHDBC dbc;
SQLHSTMT stmt;
SQLWCHAR outstr[1024];
SQLSMALLINT outstrlen;
/* Allocate an environment handle */
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
/* We want ODBC 3 support */
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
/* Allocate a connection handle */
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
/* Connect to the DSN mydsn */
string connstr = "DSN=EnglobalConn";
cout << endl << endl << "ATTEMPTING TO CONNECT TO DATA SOURCE USING:" << endl <<connstr << endl << endl;
ret = SQLDriverConnect(dbc, NULL, (SQLWCHAR*)connstr.c_str(), SQL_NTS,
outstr, sizeof(outstr), &outstrlen,
SQL_DRIVER_NOPROMPT);
if (SQL_SUCCEEDED(ret)) {
printf("Connected\n");
printf("Returned connection string was:\n\t%s\n", outstr);
if (ret == SQL_SUCCESS_WITH_INFO) {
printf("Driver reported the following diagnostics\n");
extract_error("SQLDriverConnect", dbc, SQL_HANDLE_DBC);
}
SQLDisconnect(dbc); /* disconnect from driver */
}
else {
fprintf(stderr, "Failed to connect\n");
extract_error("SQLDriverConnect", dbc, SQL_HANDLE_DBC);
}
/* free up allocated handles */
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
SQLFreeHandle(SQL_HANDLE_ENV, env);
}
int _tmain(int argc, _TCHAR* argv[])
{
do_sql();
return 0;
}
The program gives the following output. Error is the same for both 'EnglobalConn' and 'Englobal2'
SQL DATA SOURCES:
dBASE Files | Microsoft Access dBASE Driver (*dbf, *.ndx, *.mdx)
Excel Files | Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)
MS Access Database | Microsoft Access Driver (*.mdb, *.accdb)
Englobal2 | SQL Server
EnglobalConn | SQL Server
ATTEMPTING TO CONNECT TO DATA SOURCE USING:
DSN=EnglobalConn
Failed to connect
Message: [Miscrosoft][ODBC Driver Manager] Data source name not found and no default driver specified nSQLSTATE: IM002
One piece of advice I found while Googling was that a 64-bit Windows install has 2 ODBC sets, one in System32 and one in SysWOW64. I've run both and set the DSNs to be the same:
In C:\Windows\SysWOW64\odbcad32.exe:
User Data Sources: Englobal2 - SQL Server
System DSN: EnglobalConn - SQL Server
In C:\Windows\System32\odbcad32.exe:
User Data Sources: Englobal2 - SQL Server
System DSN: EnglobalConn - SQL Server
Hi I've struggled with exactly the same problem and exactly the same fail :)
(SQLWCHAR*)"DRIVER={SQL Server};SERVER=sqlserver.myhost.com, 1433;DATABASE=MyDatabase;UID=xxxxx;PWD=xxxxx",
Should be
(SQLWCHAR*)_T("DRIVER={SQL Server};SERVER=sqlserver.myhost.com, 1433;DATABASE=MyDatabase;UID=xxxxx;PWD=xxxxx"),
or
(SQLWCHAR*)TEXT("DRIVER={SQL Server};SERVER=sqlserver.myhost.com, 1433;DATABASE=MyDatabase;UID=xxxxx;PWD=xxxxx"),
Hooray! Found a solution that works:
Using the library http://otl.sourceforge.net/ (Designed for use with Oracle, but also works to connect to SQL Server):
#include "stdafx.h"
#include <iostream>
using namespace std;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define OTL_ODBC // Compile OTL 4.0/ODBC
// The following #define is required with MyODBC 3.51.11 and higher
#define OTL_ODBC_SELECT_STM_EXECUTE_BEFORE_DESCRIBE
// #define OTL_ODBC_UNIX // uncomment this line if UnixODBC is used
#include "otlv4.h" // include the OTL 4.0 header file
otl_connect db; // connect object
void insert()
// insert rows into table
{
otl_stream o(1, // buffer size should be == 1 always on INSERT
"insert into test_tab values "
"(:f1<int>, : f2<char[31]>), "
"(:f12<int>, : f22<char[31]>), "
"(:f13<int>, : f23<char[31]>), "
"(:f14<int>, : f24<char[31]>), "
"(:f15<int>, : f25<char[31]>) ",
// INSERT statement. Multiple sets of values can be used
// to work around the lack of the bulk interface
db // connect object
);
// If the number of rows to be inserted is not known in advance,
// another stream with the same INSERT can be opened
otl_stream o2(1, // buffer size should be == 1 always on INSERT
"insert into test_tab values "
"(:f1<int>, : f2<char[31]>)",
db // connect object
);
char tmp[32];
int i;
for (i = 1; i <= 100; ++i){
sprintf_s(tmp, "Name%d", i);
o << i << tmp;
}
for (i = 101; i <= 103; ++i){
sprintf_s(tmp, "Name%d", i);
o2 << i << tmp;
}
}
void update(const int af1)
// insert rows into table
{
otl_stream o(1, // buffer size should be == 1 always on UPDATE
"UPDATE test_tab "
" SET f2 = :f2<char[31]> "
" WHERE f1 = : f1<int>",
// UPDATE statement
db // connect object
);
o << "Name changed" << af1;
o << otl_null() << af1 + 1; // set f2 to NULL
}
void select(const int af1)
{
otl_stream i(50, // buffer size may be > 1
"select :f1<int>, :f2<char[31]> from test_tab "
/*"where f1 >= :f11<int> "*/,
// SELECT statement
db // connect object
);
// create select stream
cout << "Here" <<endl;
int f1;
char f2[31];
i << af1 << af1; // :f11 = af1, :f12 = af1
while (!i.eof()){ // while not end-of-data
i >> f1;
cout << "f1 = " << f1 << ", f2 = ";
i >> f2;
if (i.is_null())
cout << "NULL";
else
cout << f2;
cout << endl;
}
}
int main()
{
otl_connect::otl_initialize(); // initialize ODBC environment
try{
//db.rlogon("root / XX #mysql3532");
db.rlogon("driver={SQL Server};UID=XXXXX;PWD=XXXXXX; server=sqlserver.myserver.com"); // connect to ODBC
// db.rlogon("scott/tiger#mysql35"); // connect to ODBC, alternative format
// of connect string
otl_cursor::direct_exec
(
db,
"drop table test_table",
otl_exception::disabled // disable OTL exceptions
); // drop table
otl_cursor::direct_exec
(
db,
"create table test_table(f1 int, f2 varchar(30))"
//"create table test_tab(f1 int, f2 varchar(30)) type=innoDB" (causes MYSQL error)
); // create table
//insert(); // insert records into the table
//update(10); // update records in the table
//select(8); // select records from the table
otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (600,'Test')");
otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (-3,'Lest')");
otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (4,'Rest')");
otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (10,'Best')");
otl_cursor::direct_exec(db, "INSERT INTO test_table (f1, f2) VALUES (19,'Quest')");
//select(20);
}
catch (otl_exception& p){ // intercept OTL exceptions
cerr << "MSG: " << p.msg << endl; // print out error message
cerr << "STM_TEXT: " << p.stm_text << endl; // print out SQL that caused the error
cerr << "SQLSTATE: " << p.sqlstate << endl; // print out SQLSTATE message
cerr << "VAR_INFO: " << p.var_info << endl; // print out the variable that caused the error
}
db.logoff(); // disconnect from ODBC
return 0;
}

Data not inserted into the sqlite table c++

I am trying to save the contents of the key and value of a map into a database table. The .dbo file is created, but nothing goes into the table. It doesn't create table but it doesn't exit. I wonder what is wrong with my code.
void names_table( std::map<std::string, unsigned int> &names ){
std::string sql;
std::string str1;
std::string str2;
std::string str3;
sqlite3_stmt *stmt;
const char *file_names = create_db_file( ); /* default to temp db */
sqlite3 *db;
sqlite3_initialize( );
int rc = sqlite3_open_v2( file_names, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
if ( rc != SQLITE_OK) {
sqlite3_close( db );
cout << "Error: Database cannot open!" << endl;
exit( EXIT_FAILURE);
}
sql = "CREATE TABLE IF NOT EXISTS names_table (offset INTEGER PRIMARY KEY, stname TEXT);";
sqlite3_prepare_v2(db, sql.c_str(), sql.size(), &stmt, NULL);
if (sqlite3_step(stmt) != SQLITE_DONE) cout << "Didn't Create Table!" << endl;
for (auto pm = names.begin(); pm != names.end(); pm++) {
str2 = "'" + pm->first + "'";
char tmp[15];
sprintf(tmp,"%u",pm->second);
str3 = tmp;
str1 = (((("INSERT INTO names_table VALUES(" + str3) + ", ") + str2) + ");");
std::cout << str1 << std::endl;
sql = (char *)str1.c_str();
// stmt = NULL;
rc = sqlite3_prepare_v2(db, sql.c_str(), sql.size(), &stmt, NULL);
if ( rc != SQLITE_OK) {
sqlite3_close(db);
cout << "Error: Data cannot be inserted!" << endl;
exit ( EXIT_FAILURE);
}
}
sqlite3_close( db );
}
INSERT INTO names_table VALUES(ramsar, 8329) - I hope you're aware that string literals in SQL need to be enclosed in quotes. Try this: INSERT INTO names_table VALUES('ramsar', 8329).
EDIT: Actually, your code will never do what you want, because you're not even calling sqlite3_step after sqlite3_prepare_v2, which means that you're only compiling your SQL statement, but never evaluating it. Where did you find this bad example? See here and here decent examples on how to use the SQLite C++ interface properly.
PS: Stop messing around with sprintf in C++. You have std::stringstream for it.