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
Related
hello there im studing C and ODBC
i got error when call SQLExecDirect function.
please help me
here is the code
#include <Windows.h>
#include <sql.h>
#include <sqlext.h>
int main( void )
{
//DB connect example
SQLRETURN nResult = 0;
SQLHANDLE handleEnv = 0;
nResult = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, ( SQLHANDLE* )&handleEnv );
//nResult = SQLSetEnvAttr( handleEnv, SQL_ATTR_ODBC_VERSION, ( SQLPOINTER )SQL_OV_ODBC2, SQL_IS_INTEGER );
nResult = SQLSetEnvAttr( handleEnv, SQL_ATTR_ODBC_VERSION, ( SQLPOINTER )SQL_OV_ODBC3, SQL_IS_INTEGER );
nResult = SQLSetEnvAttr( handleEnv, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)SQL_CP_ONE_PER_HENV, SQL_IS_INTEGER);
SQLHANDLE handleDBC = 0;
nResult = SQLAllocHandle( SQL_HANDLE_DBC, handleEnv, ( SQLHANDLE* )&handleDBC );
SQLCHAR strConnect[ 256 ] = "DSN=MY TEST DB; UID=TESTsa; PWD=TESTpw";
SQLCHAR strConnectOut[ 1024 ] = {0};
SQLSMALLINT nNumOut = 0;
nResult = SQLDriverConnect( handleDBC, NULL, ( SQLCHAR* )strConnect, SQL_NTS, ( SQLCHAR* )strConnectOut, sizeof(strConnectOut),
&nNumOut, SQL_DRIVER_NOPROMPT );
SQLHSTMT handleStatement = 0;
//nResult = ::SQLAllocStmt( handleDBC, &handleStatement );
nResult = SQLAllocHandle( SQL_HANDLE_STMT, handleDBC, ( SQLHANDLE* )&handleStatement );
SQLHSTMT hstmt = handleStatement;
int sqlResultOutput = 0;
SQLINTEGER cbValue = 0;
nResult = SQLBindParameter( hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &sqlResultOutput, 0, &cbValue );
//here is the problem
nResult = SQLExecDirect( hstmt, (SQLTCHAR*) "{CALL my_TEST_SP(?)}", SQL_NTS );
//nResult Value is -1 and SQL State is 24000
return 0;
}
every call result is fine. return SQL_SUCCESS all but one
SQLExecDirect function is return -1 and SQLState is 24000
stored procedure is simple like this
CREATE PROCEDURE my_TEST_SP
#retValue int = 0 output
AS
BEGIN
SET NOCOUNT ON
SET #retValue = 0
SELECT myTestCol
FROM tTestTable
IF ##ERROR <> 0
BEGIN
SET #retValue = -1
END
END
my OS is windows7.
using visual studio 2010 sp1, sqlserver 2012
what i miss? please tell me and have a good day :)
The main difference seems to be the odbc driver version. My version is 2014.120.2000.08. I dont think it is due to the different visual studio versions - I think they all use the same odbc32.lib under the hood.
The following code works for me: I changed the stored procedure to return something that is not 0 (to verify I can actually read the data returned):
#retValue int = 0 output
AS
BEGIN
SET NOCOUNT ON
SET #retValue = 3499
SELECT myTestCol
FROM tTestTable
IF ##ERROR <> 0
BEGIN
SET #retValue = -1
END
END
And I used the following code in Visual Studio 2013:
void printErrDbc(SQLHDBC hDbc)
{
SQLSMALLINT recNr = 1;
SQLRETURN ret = SQL_SUCCESS;
while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
SQLWCHAR errMsg[SQL_MAX_MESSAGE_LENGTH + 1];
SQLWCHAR sqlState[5 + 1];
errMsg[0] = 0;
SQLINTEGER nativeError;
SQLSMALLINT cb = 0;
ret = SQLGetDiagRec(SQL_HANDLE_DBC, hDbc, recNr, sqlState, &nativeError, errMsg, SQL_MAX_MESSAGE_LENGTH + 1, &cb);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
std::wcerr << L"ERROR; native: " << nativeError << L"; state: " << sqlState << L"; msg: " << errMsg << std::endl;
}
++recNr;
}
}
void printErrStmt(SQLHSTMT hStmt)
{
SQLSMALLINT recNr = 1;
SQLRETURN ret = SQL_SUCCESS;
while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
SQLWCHAR errMsg[SQL_MAX_MESSAGE_LENGTH + 1];
SQLWCHAR sqlState[5 + 1];
errMsg[0] = 0;
SQLINTEGER nativeError;
SQLSMALLINT cb = 0;
ret = SQLGetDiagRec(SQL_HANDLE_STMT, hStmt, recNr, sqlState, &nativeError, errMsg, SQL_MAX_MESSAGE_LENGTH + 1, &cb);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
std::wcerr << L"ERROR; native: " << nativeError << L"; state: " << sqlState << L"; msg: " << errMsg << std::endl;
}
++recNr;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
//DB connect example
SQLRETURN nResult = 0;
SQLHANDLE handleEnv = 0;
nResult = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, (SQLHANDLE*)&handleEnv);
//nResult = SQLSetEnvAttr( handleEnv, SQL_ATTR_ODBC_VERSION, ( SQLPOINTER )SQL_OV_ODBC2, SQL_IS_INTEGER );
nResult = SQLSetEnvAttr(handleEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
nResult = SQLSetEnvAttr(handleEnv, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)SQL_CP_ONE_PER_HENV, SQL_IS_INTEGER);
SQLHANDLE handleDBC = 0;
nResult = SQLAllocHandle(SQL_HANDLE_DBC, handleEnv, (SQLHANDLE*)&handleDBC);
SQLWCHAR strConnect[256] = L"DSN=test;UID=sa;PWD=MySecretPassword";
SQLWCHAR strConnectOut[1024] = { 0 };
SQLSMALLINT nNumOut = 0;
nResult = SQLDriverConnect(handleDBC, NULL, (SQLWCHAR*)strConnect, SQL_NTS, (SQLWCHAR*)strConnectOut, sizeof(strConnectOut),
&nNumOut, SQL_DRIVER_NOPROMPT);
if (!SQL_SUCCEEDED(nResult))
{
printErrDbc(handleDBC);
}
SQLHSTMT handleStatement = 0;
//nResult = ::SQLAllocStmt( handleDBC, &handleStatement );
nResult = SQLAllocHandle(SQL_HANDLE_STMT, handleDBC, (SQLHANDLE*)&handleStatement);
SQLHSTMT hstmt = handleStatement;
int sqlResultOutput = 0;
SQLINTEGER cbValue = 0;
nResult = SQLBindParameter(hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &sqlResultOutput, 0, &cbValue);
//here is the problem
nResult = SQLExecDirect(hstmt, (SQLWCHAR*)L"{CALL my_TEST_SP(?)}", SQL_NTS);
if (!SQL_SUCCEEDED(nResult))
{
printErrStmt(hstmt);
}
nResult = SQLMoreResults(hstmt);
if (!(SQL_SUCCEEDED(nResult) || nResult == SQL_NO_DATA))
{
printErrStmt(hstmt);
}
std::wcout << L"Value of sqlResultOutput is: " << sqlResultOutput << std::endl;
return 0;
}
In the ODBC Data Source Administrator I created a corresponding DSN named test using ODBC Driver 11 for SQL Server with version 2014.120.2000.08. At the end the DSN entry shows the following properties (in the dialog where you can hit Test Data Source...):
Microsoft ODBC Driver for SQL Server Version 12.00.2000
Data Source Name: test
Data Source Description:
Server: .\SQLSERVERINSTANCE
Use Integrated Security: Yes
Database: Test
Language: (Default)
Data Encryption: No
Trust Server Certificate: No
Multiple Active Result Sets(MARS): No
Mirror Server:
Translate Character Data: Yes
Log Long Running Queries: No
Log Driver Statistics: No
Use Regional Settings: No
Use ANSI Quoted Identifiers: Yes
Use ANSI Null, Paddings and Warnings: Yes
If I run this sample app I get the expected output:
Value of sqlResultOutput is: 3499
So I would suggest that you try with the latest ODBC Driver for SQL Server. I think it is this download here: http://www.microsoft.com/de-ch/download/details.aspx?id=36434
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.
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);
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?
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.