I´m having a problem dealing with the connection to sql server in c++. Actually i don t know where the problem come from. I took a look at my firewall open the port 1433/1434 - on sql configuration manager i also have enable for the remote connexion. It returns the error message:
SQL DRiver message:[Microsoft][ODBC Driver 17 for SQL Server]Named Pipes Provider: Could not open a connection to SQL Server [53].
SQLState08001.
Could you help me to solve this problem?
My code looks like this:
#pragma once
using namespace std;
#include "stdafx.h"
#include <iostream>
#include <ctime>
#include <list>
#include <sqlext.h> // main SQLAPI++ header
#include <sqltypes.h>
#include <Windows.h>
#include <sql.h>
#include <cstring>
#include <string>
void showSQLError(unsigned int handletype, const SQLHANDLE& handle)
{
SQLCHAR SQLState[1024];
SQLCHAR message[1024];
if (SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, SQLState, NULL, message, 1024, NULL))
cout << "SQL DRiver message:" << message << "\nSQLState" << SQLState << "." << endl;
}
class Datapoint {
public:
time_t Date; string Name; double Value;
Datapoint() {
//default constructor to initialize Datapoint
;
}
Datapoint(time_t Dates, string Names, double Values)
{
Date = Dates;
Name = Names;
Value = Values;
}
static list<Datapoint> Timeseries(string Names)
{
list<Datapoint> data;
SQLHANDLE SQLEnvHandle = NULL;
SQLHANDLE SQLConnexionHandle = NULL;
SQLHANDLE SQLStatementHandle = NULL;
SQLRETURN retcSQLQuerystringode = 0;
int retcode;
// assigning value to string SQLQuerystring
string SQLQuerystring = "SELECT * FROM MDA..MarketData WHERE Name = '" + Names + "' order by Date Asc";
// declaring character array (+1 for null terminator)
char* SQLQuery = new char[SQLQuerystring.length() + 1];
// copying the contents of the string to char array
strcpy(SQLQuery, SQLQuerystring.c_str());
do {
// Allocate an environment handle
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &SQLEnvHandle))
{
break;
}
// Set the ODBC version environment attribute
if (SQL_SUCCESS != SQLSetEnvAttr(SQLEnvHandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0))
{
break;
}
// Allocate a connection handle
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_DBC, SQLEnvHandle, &SQLConnexionHandle))
{
break;
}
if (SQL_SUCCESS != SQLSetConnectAttr(SQLConnexionHandle, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0))
{
break;
}
SQLCHAR retConnString[1024];
switch (SQLDriverConnect(SQLConnexionHandle, NULL, (SQLCHAR*)"Driver={ODBC Driver 17 for SQL Server};Server=DESKTOP-FT3KNQR\MSSQLSERVER01;Database=MDA;UID=DESKTOP-FT3KNQR\mathi;", SQL_NTS, retConnString, 1024, NULL, SQL_DRIVER_NOPROMPT)) {
case SQL_SUCCESS:
break;
case SQL_SUCCESS_WITH_INFO:
break;
case SQL_NO_DATA_FOUND:
showSQLError(SQL_HANDLE_DBC, SQLConnexionHandle);
retcode = 1;
break;
case SQL_INVALID_HANDLE:
showSQLError(SQL_HANDLE_DBC, SQLConnexionHandle);
retcode = 1;
break;
case SQL_ERROR:
showSQLError(SQL_HANDLE_DBC, SQLConnexionHandle);
retcode = 1;
break;
default:
break;
}
if (retcode == -1)
{
break;
}
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_STMT, SQLConnexionHandle, &SQLStatementHandle))
{
break;
}
if (SQL_SUCCESS != SQLExecDirect(SQLStatementHandle, (SQLCHAR*)SQLQuery, SQL_NTS))
{
showSQLError(SQL_HANDLE_STMT, SQLStatementHandle);
break;
}
else
{
while (SQLFetch(SQLStatementHandle) == SQL_SUCCESS)
{
time_t datefromdb;
float valuesfromdb;
char* namesfromdb = new char[256];
SQLGetData(SQLStatementHandle, 1, SQL_C_DEFAULT, &datefromdb, sizeof(datefromdb), NULL);
SQLGetData(SQLStatementHandle, 2, SQL_C_DEFAULT, &namesfromdb, sizeof(namesfromdb), NULL);
SQLGetData(SQLStatementHandle, 3, SQL_C_DEFAULT, &valuesfromdb, sizeof(valuesfromdb), NULL);
Datapoint datapointsql;
datapointsql.Date = datefromdb;
datapointsql.Name = namesfromdb;
datapointsql.Value = valuesfromdb;
data.push_back(datapointsql);
}
}
} while (FALSE);
// Free the statement handle
SQLFreeHandle(SQL_HANDLE_STMT, SQLStatementHandle);
// Disconnect from the SQL Server
SQLDisconnect(SQLStatementHandle);
// Free the connection and environment handles
SQLFreeHandle(SQL_HANDLE_DBC, SQLConnexionHandle);
SQLFreeHandle(SQL_HANDLE_ENV, SQLEnvHandle);
return data;
}
};
using namespace std;
#include "stdafx.h"
#include <iostream>
#include <ctime>
#include <list>
#include <sqlext.h> // main SQLAPI++ header
#include <sqltypes.h>
#include <Windows.h>
#include <sql.h>
#include <cstring>
#include <string>
#include "Class_Datapoint.h"
int main()
{
list<Datapoint> data = Datapoint::Timeseries("CCC");
return 0;
}
I took a look at my firewall open the port 1433/1434 - on sql configuration manager i also have enable for the remote connexion. The connexion with the database doesn t work.I am using a windows authentification without password. Server name:DESKTOP-FT3KNQR\MSSQLSERVER01 / User name:DESKTOP-FT3KNQR\mathi/ without password.
Related
I'm testing the behaviour of how SQL Server's ODBC driver returns output parameters, and I've come up with the following test program:
#include <windows.h>
#define SQL_NOUNICODEMAP
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>
#include <algorithm>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <queue>
#include <utility>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <thread>
#include <tuple>
#include <vector>
#include <cassert>
using namespace std;
/// #brief Global variable indicating if the application is connected to the driver/data source.
bool g_isConnected = false;
/// #brief Check if an ODBC call failed and display the SQLState, native error code,
/// and error message on stderr.
///
/// #param rc The return code.
/// #param stmt The statement handle.
/// #param conn The connection handle.
/// #param env The environment handle.
///
/// #return true If the API call was successful.
SQLRETURN CheckDiagnostics(SQLRETURN rc, SQLHANDLE stmt, SQLHANDLE conn = SQL_NULL_HANDLE, SQLHANDLE env = SQL_NULL_HANDLE)
{
if (SQL_ERROR == rc || SQL_SUCCESS_WITH_INFO == rc)
{
char stateBuffer[6];
char msgBuffer[1024];
SQLINTEGER nativeError;
SQLError(
env,
conn,
stmt,
reinterpret_cast<SQLCHAR*>(stateBuffer),
&nativeError,
reinterpret_cast<SQLCHAR*>(msgBuffer),
sizeof(msgBuffer),
NULL);
cerr << (SQL_ERROR == rc ? "ERROR" : "WARNING") << ": [" << stateBuffer << "] (" << nativeError << "): " << msgBuffer << endl;
}
return rc;
}
SQLRETURN CheckDiagnosticsFatal(SQLRETURN rc, SQLSMALLINT handleType, SQLHANDLE handle)
{
if (SQL_ERROR == rc || SQL_SUCCESS_WITH_INFO == rc)
{
char stateBuffer[6];
char msgBuffer[1024];
SQLINTEGER nativeError;
for (SQLSMALLINT rec = 1; SQL_NO_DATA != SQLGetDiagRec(handleType, handle, rec, reinterpret_cast<SQLCHAR*>(stateBuffer), &nativeError, reinterpret_cast<SQLCHAR*>(msgBuffer), sizeof(msgBuffer), NULL); ++rec)
{
cerr << (SQL_ERROR == rc ? "ERROR" : "WARNING") << ": [" << stateBuffer << "] (" << nativeError << "): " << msgBuffer << endl;
}
if (SQL_ERROR == rc)
{
exit(-1);
}
}
return rc;
}
/// #brief Clean up the handles passed in.
void CleanupHandles(SQLHANDLE stmt, SQLHANDLE dbc, SQLHANDLE env)
{
if (SQL_NULL_HANDLE != stmt)
{
SQLFreeStmt(stmt, SQL_CLOSE);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
}
if (g_isConnected)
{
g_isConnected = false;
SQLDisconnect(dbc);
}
if (SQL_NULL_HANDLE != dbc)
{
SQLFreeHandle(SQL_HANDLE_DBC, dbc);
}
if (SQL_NULL_HANDLE != env)
{
SQLFreeHandle(SQL_HANDLE_ENV, env);
}
}
/// #brief Check if an ODBC call failed and display the SQLState, native error code,
/// and error message on stderr. Abort execution if the return code was SQL_ERROR.
///
/// #param rc The return code.
/// #param stmt The statement handle.
/// #param conn The connection handle.
/// #param env The environment handle.
SQLRETURN CheckDiagnosticsFatal(SQLRETURN rc, SQLHANDLE stmt, SQLHANDLE conn = SQL_NULL_HANDLE, SQLHANDLE env = SQL_NULL_HANDLE)
{
CheckDiagnostics(rc, stmt, conn, env);
if (SQL_ERROR == rc)
{
CleanupHandles(stmt, conn, env);
exit(-1);
}
return rc;
}
int main(int argc, char* argv[])
{
// Connect to the DSN and allocate a statement handle
SQLHANDLE env = SQL_NULL_HANDLE;
SQLHANDLE dbc = SQL_NULL_HANDLE;
SQLHANDLE stmt = SQL_NULL_HANDLE;
CheckDiagnosticsFatal(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env), stmt, dbc, env);
CheckDiagnosticsFatal(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0), stmt, dbc, env);
CheckDiagnosticsFatal(SQLSetEnvAttr(env, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER)SQL_CP_ONE_PER_HENV, 0), stmt, dbc, env);
SQLCHAR outConnBuffer[1024];
SQLSMALLINT outLen;
CheckDiagnosticsFatal(SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc), stmt, dbc, env);
CheckDiagnosticsFatal(SQLDriverConnect(
dbc,
NULL,
(SQLCHAR*)"DSN=SqlServer",
SQL_NTS,
outConnBuffer,
sizeof(outConnBuffer),
&outLen,
SQL_DRIVER_NOPROMPT),
stmt,
dbc,
env);
CheckDiagnosticsFatal(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt), stmt, dbc, env);
CheckDiagnosticsFatal(SQLSetStmtAttr(stmt, SQL_ATTR_PARAMSET_SIZE, (void*)(SQLULEN)2, 0), stmt);
SQLCHAR inputParamBuffer[2][10] = { "1", "2" };
SQLLEN inputParamLenInd[2] = { SQL_NTS, SQL_NTS };
SQLINTEGER outputParamBuffer[2] = { 0, 0 };
SQLLEN outputParamLenInd[2];
CheckDiagnosticsFatal(SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 10, 0, &inputParamBuffer, sizeof(inputParamBuffer[0]), inputParamLenInd), stmt);
CheckDiagnosticsFatal(SQLBindParameter(stmt, 2, SQL_PARAM_INPUT_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &outputParamBuffer, sizeof(outputParamBuffer[0]), outputParamLenInd), stmt);
// const SQLSMALLINT unnamedValue(SQL_UNNAMED);
//
// SQLHDESC ipd;
// CheckDiagnosticsFatal(SQLGetStmtAttr(stmt, SQL_ATTR_IMP_PARAM_DESC, &ipd, 0, 0), stmt);
// CheckDiagnosticsFatal(SQLSetDescField(ipd, 1, SQL_DESC_NAME, "#inparam", SQL_NTS), SQL_HANDLE_DESC, ipd);
// CheckDiagnosticsFatal(SQLSetDescField(ipd, 1, SQL_DESC_UNNAMED, (SQLPOINTER)unnamedValue, SQL_IS_SMALLINT), SQL_HANDLE_DESC, ipd);
// CheckDiagnosticsFatal(SQLSetDescField(ipd, 2, SQL_DESC_NAME, "#outparam", SQL_NTS), SQL_HANDLE_DESC, ipd);
// CheckDiagnosticsFatal(SQLSetDescField(ipd, 2, SQL_DESC_UNNAMED, (SQLPOINTER)unnamedValue, SQL_IS_SMALLINT), SQL_HANDLE_DESC, ipd);
SQLSMALLINT paramStatus[2];
CheckDiagnosticsFatal(SQLSetStmtAttr(stmt, SQL_ATTR_PARAM_STATUS_PTR, paramStatus, 0), stmt);
// Prepare the query, and then execute/fetch in a loop.
SQLCHAR* const query((SQLCHAR*)"{CALL TestV1.dbo.TestLateOutput4(?)}");
cout << "Preparing query: " << query << endl;
if (SQL_SUCCEEDED(CheckDiagnostics(SQLPrepare(stmt, query, SQL_NTS), stmt)))
{
cout << "Executing query..." << endl;
CheckDiagnosticsFatal(SQLExecute(stmt), stmt);
//while (SQL_NO_DATA != CheckDiagnosticsFatal(SQLFetch(stmt), stmt));
CheckDiagnosticsFatal(SQLMoreResults(stmt), stmt);
//while (SQL_NO_DATA != CheckDiagnosticsFatal(SQLFetch(stmt), stmt));
CheckDiagnosticsFatal(SQLMoreResults(stmt), stmt);
CleanupHandles(stmt, dbc, env);
return EXIT_SUCCESS;
}
else
{
cout << "Failed to prepare query." << endl;
CheckDiagnosticsFatal(SQL_ERROR, stmt);
abort();
}
}
The stored procedure that it's invoking, TestV1.dbo.TestLateOutput4 has been created by executing the following:
create procedure TestLateOutput4 #inparam varchar(10), #outparam int output
as
select 1
SET #outparam = #inparam
return
The problem I'm getting is that SQLExecute is returning SQL_SUCCESS_WITH_INFO (setting all of the parameter set statuses to SQL_PARAM_ERROR), with the message [42000] (201): [Microsoft][SQL Server Native Client 11.0][SQL Server]Procedure or function 'TestLateOutput4' expects parameter '#outparam', which was not supplied.
As far as I can tell, I did supply both parameters needed (by binding parameters 1 & 2). I also tried setting the parameter names (see the commented out lines setting SQL_DESC_NAME), but that didn't change anything. I also tried explicitly setting SQL_DESC_UNNAMED to SQL_UNNAMED (even though that should be the default), but nothing.
The other thing I tried was to bind the second parameter as input/output (because I know that SQL Server treats 'output' parameters that way), originally I was just binding it as output.
What am I doing wrong?
I created a sample service using Win32 API and C++.
I have once used Mingw g++ (7.1 - C++14) and Visual Studio 2010 independently.
The service I created using g++ does not start (after installation) and gives Error 1053: "The service did not respond in a timely fashion" when attempting to start, stop or pause a service.
I created an service using Visual C++ 2010 (same code with minor modification - for Unicode support) and it run properly on development machine (after installation).
However when I run the same service (after installation) I get error Error 1053: "The service did not respond in a timely fashion" when attempting to start, stop or pause a service .
Reference Article : Simple Windows Service in C++
Visual C++ :
WindowsService.cpp
#include "stdafx.h"
#include "Common.hpp"
using namespace std;
/*
*
*/
SERVICE_STATUS serviceStatus = {0};
SERVICE_STATUS_HANDLE serviceStatusHandle = NULL;
HANDLE serviceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain (DWORD, LPSTR *);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID);
#define SERVICE_NAME _T("My Sample Service")
int _tmain(int argc, _TCHAR* argv[])
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if(StartServiceCtrlDispatcher(serviceTable) == FALSE)
{
DWORD errorMessageID = ::GetLastError();
FileOperations fo;
fo.printError(fo.getLastErrorAsString(errorMessageID));
return errorMessageID;
}
//cout << "Hello World";
FileOperations fo;
fo.printError("Testing Error");
fo.printLog("Ishaan Says Hello World");
return 0;
}
VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
{
DWORD status = E_FAIL;
serviceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if(serviceStatusHandle == NULL)
{
FileOperations fo;
fo.printError(fo.getLastErrorAsString(::GetLastError()));
return;
}
//Tell The Service Controller we are starting
ZeroMemory(&serviceStatus, sizeof(serviceStatus));
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service : Service Main : SetSeviceStatus returned error. First (1) If"));
FileOperations fo;
fo.printError("My Sample Service : Service Main : SetSeviceStatus returned error");
}
//Preform task necessary to start a service here
//Create a stop event to wait on later
serviceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(serviceStopEvent == NULL)
{
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP;
serviceStatus.dwWin32ExitCode = GetLastError();
serviceStatus.dwCheckPoint = 1;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service : ServiceMain : SetServiceStatus returned error. Second (2) If"));
FileOperations fo;
fo.printError("My Sample Service : ServiceMain : SetServiceStatus returned error. Second (2) If");
}
return;
}
//Tell Service Controller we are started
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
serviceStatus.dwCurrentState = SERVICE_RUNNING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service : ServiceMain : SetServiceStatus returned error. Tell Service Controller we are started"));
FileOperations fo;
fo.printError("My Sample Service : ServiceMain : SetServiceStatus returned error. Tell Service Controller we are started");
}
// Start a thread that will perform the main task of the service
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
// Wait until our worker thread exits signaling that the service needs to stop
WaitForSingleObject(hThread, INFINITE);
//Perform Clean Up
CloseHandle(serviceStopEvent);
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 3;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service : Service Main : SetSeviceStatus returned error during exiting"));
FileOperations fo;
fo.printError("My Sample Service : Service Main : SetSeviceStatus returned error during exiting");
}
return;
}
VOID WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
switch(ctrlCode)
{
case SERVICE_CONTROL_STOP :
if(serviceStatus.dwCurrentState != SERVICE_RUNNING)
break;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 4;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString(_T("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error"));
FileOperations fo;
fo.printError("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error");
}
SetEvent(serviceStopEvent);
break;
default :
break;
}
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
while(WaitForSingleObject(serviceStopEvent, 0) != WAIT_OBJECT_0)
{
FileOperations fo;
fo.printLog("Inside Service Thread");
Sleep(1000);
}
return ERROR_SUCCESS;
}
Common.hpp
#ifndef COMMON_COMMON_HPP_
#define COMMON_COMMON_HPP_
#include "stdafx.h"
using namespace std;
#define RETURN_SUCCESS true
#define RETURN_FAILURE false
class FileOperations
{
public :
void printError(string);
void printLog(string);
string getLastErrorAsString(DWORD);
private :
void getDateTime(void);
string DateTime;
};
stdafx.h
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <ctime>
#include <cerrno>
#include <string>
#include <cstdio>
#include <fstream>
#include <string>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <Windows.h>
Common.cpp
#include "stdafx.h"
#include "Common.hpp"
using namespace std;
bool GlobalVariables::startCapture = false;
void FileOperations::printLog(string str)
{
ofstream of;
of.open("C:\Log.dat", ios::out | ios::app);
this->getDateTime();
of << "[" << DateTime << "]" << "\t\t" << str << endl;
of.close();
}
void FileOperations::printError(string str)
{
ofstream of;
of.open("C:\Error.dat", ios::out | ios::app);
this->getDateTime();
of << "[" << DateTime << "]" << "\t\t" << str << endl;
of.close();
}
void FileOperations::getDateTime(void)
{
time_t now;
tm *dtStruct;
now = time(0);
dtStruct = localtime(&now);
DateTime.clear();
DateTime = to_string((long long)dtStruct->tm_mday) + ":" + to_string((long long)1 + dtStruct->tm_mon) + ":" + to_string((long long)1900 + dtStruct->tm_year) + "\t" +
to_string((long long)1 + dtStruct->tm_hour) + ":" + to_string((long long)1 + dtStruct->tm_min) + ":" + to_string((long long)1 + dtStruct->tm_sec);
}
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
string FileOperations::getLastErrorAsString(DWORD errorMessageID)
{
if(errorMessageID == 0)
return string("No error message has been recorded"); //No error message has been recorded
LPSTR messageBuffer = nullptr;
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
string message(messageBuffer, size);
//Free the buffer.
LocalFree(messageBuffer);
return message;
}
g++ :
main.cpp
#include "Common.hpp"
using namespace std;
/*
*
*/
SERVICE_STATUS serviceStatus = {0};
SERVICE_STATUS_HANDLE serviceStatusHandle = NULL;
HANDLE serviceStopEvent = INVALID_HANDLE_VALUE;
VOID WINAPI ServiceMain (DWORD, LPSTR *);
VOID WINAPI ServiceCtrlHandler(DWORD);
DWORD WINAPI ServiceWorkerThread(LPVOID);
#define SERVICE_NAME "My Sample Service"
int main(int argc, char** argv)
{
SERVICE_TABLE_ENTRY serviceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
{NULL, NULL}
};
if(StartServiceCtrlDispatcher(serviceTable) == FALSE)
{
DWORD errorMessageID = ::GetLastError();
FileOperations fo;
fo.printError(fo.getLastErrorAsString(errorMessageID));
return errorMessageID;
}
//cout << "Hello World";
FileOperations fo;
fo.printError("Testing Error");
fo.printLog("Ishaan Says Hello World");
return 0;
}
VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
{
DWORD status = E_FAIL;
serviceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if(serviceStatusHandle == NULL)
{
FileOperations fo;
fo.printError(fo.getLastErrorAsString(::GetLastError()));
return;
}
//Tell The Service Controller we are starting
ZeroMemory(&serviceStatus, sizeof(serviceStatus));
serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service : Service Main : SetSeviceStatus returned error. First (1) If");
FileOperations fo;
fo.printError("My Sample Service : Service Main : SetSeviceStatus returned error");
}
//Preform task necessary to start a service here
//Create a stop event to wait on later
serviceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if(serviceStopEvent == NULL)
{
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP;
serviceStatus.dwWin32ExitCode = GetLastError();
serviceStatus.dwCheckPoint = 1;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service : ServiceMain : SetServiceStatus returned error. Second (2) If");
FileOperations fo;
fo.printError("My Sample Service : ServiceMain : SetServiceStatus returned error. Second (2) If");
}
return;
}
//Tell Service Controller we are started
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
serviceStatus.dwCurrentState = SERVICE_RUNNING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 0;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service : ServiceMain : SetServiceStatus returned error. Tell Service Controller we are started");
FileOperations fo;
fo.printError("My Sample Service : ServiceMain : SetServiceStatus returned error. Tell Service Controller we are started");
}
// Start a thread that will perform the main task of the service
HANDLE hThread = CreateThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);
// Wait until our worker thread exits signaling that the service needs to stop
WaitForSingleObject(hThread, INFINITE);
//Perform Clean Up
CloseHandle(serviceStopEvent);
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 3;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service : Service Main : SetSeviceStatus returned error during exiting");
FileOperations fo;
fo.printError("My Sample Service : Service Main : SetSeviceStatus returned error during exiting");
}
return;
}
VOID WINAPI ServiceCtrlHandler(DWORD ctrlCode)
{
switch(ctrlCode)
{
case SERVICE_CONTROL_STOP :
if(serviceStatus.dwCurrentState != SERVICE_RUNNING)
break;
serviceStatus.dwControlsAccepted = 0;
serviceStatus.dwCurrentState = SERVICE_STOP_PENDING;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCheckPoint = 4;
if(SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE)
{
OutputDebugString("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error");
FileOperations fo;
fo.printError("My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error");
}
SetEvent(serviceStopEvent);
break;
default :
break;
}
}
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
while(WaitForSingleObject(serviceStopEvent, 0) != WAIT_OBJECT_0)
{
FileOperations fo;
fo.printLog("Inside Service Thread");
Sleep(1000);
}
}
Common.cpp
#include "Common.hpp"
using namespace std;
bool GlobalVariables::startCapture = false;
void FileOperations::printLog(string str)
{
ofstream of;
of.open("Log.dat", ios::out | ios::app);
this->getDateTime();
of << "[" << DateTime << "]" << "\t\t" << str << endl;
of.close();
}
void FileOperations::printError(string str)
{
ofstream of;
of.open("Error.dat", ios::out | ios::app);
this->getDateTime();
of << "[" << DateTime << "]" << "\t\t" << str << endl;
of.close();
}
void FileOperations::getDateTime(void)
{
time_t now;
tm *dtStruct;
now = time(0);
dtStruct = localtime(&now);
DateTime.clear();
DateTime = to_string(dtStruct->tm_mday) + ":" + to_string(1 + dtStruct->tm_mon) + ":" + to_string(1900 + dtStruct->tm_year) + "\t" +
to_string(1 + dtStruct->tm_hour) + ":" + to_string(1 + dtStruct->tm_min) + ":" + to_string(1 + dtStruct->tm_sec);
}
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
string FileOperations::getLastErrorAsString(DWORD errorMessageID)
{
if(errorMessageID == 0)
return string("No error message has been recorded"); //No error message has been recorded
LPSTR messageBuffer = nullptr;
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
string message(messageBuffer, size);
//Free the buffer.
LocalFree(messageBuffer);
return message;
}
Common.hpp
#ifndef COMMON_COMMON_HPP_
#define COMMON_COMMON_HPP_
using namespace std;
#include <ctime>
#include <cerrno>
#include <string>
#include <cstdio>
#include <thread>
#include <fstream>
#include <string>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <cstdbool>
#include <iostream>
#include <windows.h>
//#include <pthread.h>
//#include "CommandList.hpp"
#define RETURN_SUCCESS true
#define RETURN_FAILURE false
class FileOperations
{
public :
void printError(string);
void printLog(string);
string getLastErrorAsString(DWORD);
private :
void getDateTime(void);
string DateTime;
};
class GlobalVariables
{
public :
static bool startCapture;
};
#endif /* COMMON_COMMON_HPP_ */
I used administrative account to install and run the service.
Program seems to work, but can't figure out why its not running second part of code. For example, when I compile and execute msg2.cpp it prompts user to 'Enter some text'. When user inputs text msg1.cpp displays user input. The issue is msg1.cpp is not prompting user 'Enter some text'. Any suggestions on how I can receive and send message alternatively?
//msg2.cpp
/* The sender program is very similar to msg1.cpp. In the main set up, delete the
msg_to_receive declaration and replace it with buffer[BUFSIZ], remove the message
queue delete and make the following changes to the running loop.
We now have a call to msgsnd to send the entered text to the queue. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512
struct my_msg_st {
long int my_msg_type;
char some_text[MAX_TEXT];
};
int main()
{
int running = 1;
struct my_msg_st some_data;
int msgid;
char buffer[BUFSIZ];
long int msg_to_receive = 0;
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
while(running) {
printf("Enter some text: ");
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
}
/* Then the messages are retrieved from the queue, until an end message is encountered.
Lastly, the message queue is deleted. */
while(running) {
if (msgrcv(msgid, (void *)&some_data, BUFSIZ,
msg_to_receive, 0) == -1) {
fprintf(stderr, "msgrcv failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0) {
running = 0;
}
}
if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
//msg1.cpp
/* Here's the receiver program. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MAX_TEXT 512
//string UserInput(string);
struct my_msg_st {
long int my_msg_type;
char some_text[BUFSIZ];
//char some_text[MAX_TEXT];
};
int main()
{
int running = 1;
int msgid;
struct my_msg_st some_data;
long int msg_to_receive = 0;
char buffer[BUFSIZ];
char some_text[MAX_TEXT];
//string input;
/* First, we set up the message queue. */
msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
if (msgid == -1) {
fprintf(stderr, "msgget failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
/* Then the messages are retrieved from the queue, until an end message is encountered.
Lastly, the message queue is deleted. */
while(running) {
if (msgrcv(msgid, (void *)&some_data, BUFSIZ,
msg_to_receive, 0) == -1) {
fprintf(stderr, "msgrcv failed with error: %d\n", errno);
exit(EXIT_FAILURE);
}
printf("You wrote: %s", some_data.some_text);
if (strncmp(some_data.some_text, "end", 3) == 0) {
running = 0;
}
}
if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
// Need to reset value, before entering second loop
// At this point, value enters loop, prompts user enter text
while(running) {
printf("Enter some text: ");
for (int i = 1; i < running; i++){
fgets(buffer, BUFSIZ, stdin);
some_data.my_msg_type = 1;
strcpy(some_data.some_text, buffer);
}
if (msgsnd(msgid, (void *)&some_data, MAX_TEXT, 0) == -1) {
fprintf(stderr, "msgsnd failed\n");
exit(EXIT_FAILURE);
}
if (strncmp(buffer, "end", 3) == 0) {
running = 0;
}
}
exit(EXIT_SUCCESS);
}
My .02 currency units are on this snippet from msg1.cpp:
if (msgctl(msgid, IPC_RMID, 0) == -1) {
fprintf(stderr, "msgctl(IPC_RMID) failed\n");
exit(EXIT_FAILURE);
}
You seem to delete the message queue here as soon as the 'end' message has been received.
(Also: fprintf() & friends in C++ program?)
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.
I have created a MySQL table where one of the columns stores a BLOB type. (The Internet told me BLOB is the correct data type for images.)
I am pretty much a beginner with both C++ and MySQL. What I would like to do is to write a small program with a main() that puts a jpeg into that table. For the sake of this exercise, I do not want to store a reference to a directory that contains an image.
Am I wrong to think that it is as simple as filling out the part in BLOCK 2 below?
#include <iostream>
#include <string>
#include <mysql.h>
using namespace std;
int main(int argc, char **argv)
{
//BLOCK 1: INIT
MYSQL *connection, mysql;
MYSQL_RES *result;
MYSQL_ROW row;
int query_state;
mysql_init(&mysql);
connection = mysql_real_connect(&mysql, "localhost", "root", "secret", "beginner_db",0,0,0);
//BLOCK 2: SEND QUERY
/* do something to insert image to table */
//BLOCK 3: DISPLAY QUERY RESULTS
result = mysql_store_result(connection);
/* do something with result */
//BLOCK 4: FREE
mysql_free_result(result);
mysql_close(connection);
return 0;
}
For this scenario, a good solution would be to use the mysql_stmt_send_long_data() function.
There is an example on the MySQL Manual page that I linked to, but here is a more relevant example of sending file contents:
#ifdef _WIN32
#include <windows.h>
#endif
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <boost/scope_exit.hpp>
#include <mysql.h>
#define ARR_LEN(arr_id) ((sizeof (arr_id))/(sizeof (arr_id)[0]))
int main()
{
using namespace std;
MYSQL *pconn = mysql_init(NULL);
BOOST_SCOPE_EXIT( (pconn) ) {
mysql_close(pconn);
} BOOST_SCOPE_EXIT_END
const char *db_name = "test";
if (!mysql_real_connect(pconn, "localhost", "test", "********", db_name, 0, NULL, CLIENT_COMPRESS)) {
cerr << "Error: mysql_real_connect() failed to connect to `" << db_name << "`." << endl;
return EXIT_FAILURE;
}
MYSQL_STMT *pinsert_into_images_stmt = mysql_stmt_init(pconn);
BOOST_SCOPE_EXIT( (pinsert_into_images_stmt) ) {
mysql_stmt_close(pinsert_into_images_stmt);
} BOOST_SCOPE_EXIT_END
const char sql1[] = "INSERT INTO images(data) VALUES (?)";
if (mysql_stmt_prepare(pinsert_into_images_stmt, sql1, strlen(sql1)) != 0) {
cerr << "Error: mysql_stmt_prepare() failed to prepare `" << sql1 << "`." << endl;
return EXIT_FAILURE;
}
MYSQL_BIND bind_structs[] = {
{ 0 } // One for each ?-placeholder
};
unsigned long length0;
bind_structs[0].length = &length0;
bind_structs[0].buffer_type = MYSQL_TYPE_BLOB;
bind_structs[0].is_null_value = 0;
if (mysql_stmt_bind_param(pinsert_into_images_stmt, bind_structs) != 0) {
cerr << "Error: mysql_stmt_bind_param() failed." << endl;
return EXIT_FAILURE;
}
const char *file_name = "image.jpg";
FILE *fp = fopen(file_name, "rb");
BOOST_SCOPE_EXIT( (fp) ) {
fclose(fp);
} BOOST_SCOPE_EXIT_END
// Use mysql_stmt_send_long_data() to send the file data in chunks.
char buf[10*1024];
while (!ferror(fp) && !feof(fp)) {
size_t res = fread(buf, 1, ARR_LEN(buf), fp);
if (mysql_stmt_send_long_data(pinsert_into_images_stmt, 0, buf, res) != 0) {
cerr << "Error: mysql_stmt_send_long_data() failed." << endl;
return EXIT_FAILURE;
}
}
if (!feof(fp)) {
cerr << "Error: Failed to read `" << file_name << "` in its entirety." << endl;
return EXIT_FAILURE;
}
if (mysql_stmt_execute(pinsert_into_images_stmt) != 0) {
cerr << "Error: mysql_stmt_execute() failed." << endl;
return EXIT_FAILURE;
}
cout << "Inserted record #" << mysql_insert_id(pconn) << endl;
return EXIT_SUCCESS;
}
I am using the following definition of table `images`:
CREATE TABLE images (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data MEDIUMBLOB NOT NULL,
PRIMARY KEY (id)
);
Upon running this program, it successfully sent the 38,339-byte JPEG image.jpg to the server and outputted "Inserted record #1".
You can verify that the correct number of bytes were sent:
mysql> SELECT octet_length(data) FROM images WHERE id=1;
+--------------------+
| octet_length(data) |
+--------------------+
| 38339 |
+--------------------+
1 row in set (0.00 sec)
I found this solution that worked... for images under 10kb.
//http://zetcode.com/tutorials/mysqlcapitutorial/
//g++ -o output source.cpp $(mysql_config --cflags) $(mysql_config --libs)
#include <stdio.h>
#include <iostream>
#include <mysql.h>
int main(int argc, char **argv)
{
MYSQL *conn;
int len, size;
char data[1000*1024];
char chunk[2*1000*1024+1];
char query[1024*5000];
FILE *fp;
conn = mysql_init(NULL);
mysql_real_connect(conn, "localhost", "root", "secret", "beginner_db", 0, NULL, 0);
fp = fopen("filename.png", "rb");
size = fread(data, 1, 1024*1000, fp);
mysql_real_escape_string(conn, chunk, data, size);
char *stat = "INSERT INTO pic_tbl(name, pic) VALUES('cexample', '%s')";
len = snprintf(query, sizeof(stat)+sizeof(chunk) , stat, chunk);
mysql_real_query(conn, query, len);
fclose(fp);
mysql_close(conn);
}
Something like this:
CString SaveFile( CMemoryFile& File )
{
*pFileKey = -1;
SQLRETURN retcode;
SQLHSTMT hstmt;
CLoggEntryList LoggEntryList( this ); // logg entries cannot be made while busy inside the hstmt, use this class to add them later
SQLINTEGER cbDocumentBlock; // For binding the main image
long lDocumentBufferSize = 0;
unsigned char* pDocumentBuffer; // Will be set to point to the buffer that should be written into the document blob field
unsigned char pDummyChar[] = {'0'}; // Dummy buffer to write in the image/thumbnail blob fields when using external storage
lDocumentBufferSize = File.m_lBufferSize;
pDocumentBuffer = File.m_pFileBuffer;
// Allocate statement handle
retcode = SQLAllocHandle(SQL_HANDLE_STMT, m_Database.m_hdbc, &hstmt);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{ // Create a result set
CString szSQL;
szSQL = ( "INSERT INTO ObjectTable (ObjectData) VALUES ( ? )");
retcode = SQLPrepare(hstmt, (SQLCHAR*)szSQL.GetBuffer(), SQL_NTS);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
// Bind the parameters. For parameter 1, pass the parameter number in ParameterValuePtr instead of a buffer address.
SQLINTEGER cbNULL = 0;
SQLINTEGER cbTEXT = SQL_NTS;
int nColumn = 1;
// Bind ObjectData
cbDocumentBlock = SQL_LEN_DATA_AT_EXEC(0); //SQL_LEN_DATA_AT_EXEC(lImageBufferSize);
retcode = SQLBindParameter(hstmt, nColumn++, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
0, 0, (SQLPOINTER) DOCUMENT, 0, &cbDocumentBlock);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
// Set values so data for parameter 1 will be passed at execution. Note that the length parameter in
// the macro SQL_LEN_DATA_AT_EXEC is 0. This assumes that the driver returns "N" for the
// SQL_NEED_LONG_DATA_LEN information type in SQLGetInfo.
retcode = SQLExecute(hstmt);
const long nMaxChunkSize = 400000;
// For data-at-execution parameters, call SQLParamData to get the parameter number set by SQLBindParameter.
// Call InitUserData. Call GetUserData and SQLPutData repeatedly to get and put all data for the parameter.
// Call SQLParamData to finish processing this parameter.
while (retcode == SQL_NEED_DATA)
{
SQLPOINTER pToken;
retcode = SQLParamData(hstmt, &pToken);
switch( (int)pToken )
{
case DOCUMENT:
{
if (retcode == SQL_NEED_DATA)
{
for( int nPos = 0; nPos < lDocumentBufferSize; nPos += nMaxChunkSize )
{
int nBufferSize = min( lDocumentBufferSize - nPos, nMaxChunkSize );
SQLRETURN retcode2 = SQLPutData(hstmt, pDocumentBuffer+nPos, nBufferSize );
if (retcode2 != SQL_SUCCESS && retcode2 != SQL_SUCCESS_WITH_INFO)
{
SQLCHAR Sqlstate[6];
SQLINTEGER NativeError;
SQLCHAR MessageText[201];
SQLSMALLINT TextLengthPtr;
retcode2 = SQLGetDiagRec( SQL_HANDLE_STMT, hstmt, 1, Sqlstate, &NativeError, MessageText, 200, &TextLengthPtr );
if (retcode2 == SQL_SUCCESS || retcode2 == SQL_SUCCESS_WITH_INFO)
{
MessageText[TextLengthPtr] = 0;
Sqlstate[5] = 0;
CString szSQLState( Sqlstate );
CString szMessageText( MessageText );
CString szMessage;
szMessage.Format("Error in SaveFile(). SQL State %s. Native %ld. Source: %s", szSQLState, NativeError, szMessageText );
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return szMessage;
}
}
}
}
break;
}
default:
{
CString szMessage;
szMessage.Format("Error in SaveBuffer(). Unknown parameter buffer.");
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return szMessage;
}
break;
}
}
}
SQLRETURN retcode3;
retcode3 = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
ASSERT(retcode3 == SQL_SUCCESS);
}
}
}
This code is not tested or even compiled, but it should point you in the right direction.