copy record set in local _RecordsetPtr in C++ - c++

I have getResults function and executing a query in C++.
int ABC::getResult(char *query)
{
_CommandPtr pCom;
_bstr_t lv_query;
lv_query = (_bstr_t) sqlQuery;
try
{
pCom.CreateInstance(__uuidof(Command));
pCom->ActiveConnection = pConn;
pCom->CommandType = adCmdText;
pCom->CommandText = lv_query;
pCom->CommandTimeout = 60;
RecordSet = pCom->Execute(NULL, NULL, adCmdText);
}
catch(_com_error &e)
{
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
sprintf_s(errStr,sizeof(errStr), "Exception:Failed to get detail from database.");
return ERR_EXCEPPTION;
}
I have to copy the _RecordsetPtr RecordSet of this function which is a public member of ABD class.
I am doing like below:
ABC class will make the connection to Database.
ABC mConnect;
mConnect.getResults(query);
_RecordsetPtr lv_set = std::move(mConnect.RecordSet);
mConnect.CloseConnection();
Above std::move is not working , and I get lv_set as null;
I want to achieve that once I take recordset in local copy , I want to close the DB connection and proceed with local recordset to fetch the results
Is there any way to achieve it?
Update:
no had not implement the move ctor
Rather we have similar function as below,
and it give proper RecordSet when I do
_RecordsetPtr lv_set = std::move(mConnect.RecordSet);
int ABC::getResults (char *sqlQuery)
{
_bstr_t lv_query;
lv_query = (_bstr_t) sqlQuery;
CString lv_error_log;
// Define Other Variables
HRESULT hr = S_OK;
_variant_t index;
index.vt = VT_I2;
try
{
// Open recordset from Authors table.
hr = RecordSet.CreateInstance(__uuidof(Recordset));
if(FAILED(hr))
{
return -1;
}
RecordSet->CursorLocation = adUseClient;
// Pass the Cursor type and Lock type to the Recordset.
RecordSet->Open (lv_query, strConn, adOpenDynamic,
adLockBatchOptimistic, adCmdText);
}
return QRY_EXECUTE_SUCCESS;
}

Related

How to fix Connection execute error using ADO in C++

I'm using ado to connect SQL Server in my C++ project.
So I want to insert/update my database and I wrote some queries (see the code) and I'm trying to execute my connection or command.
But it goes on an error at pConnection->Execute(InsertQuery, NULL, adCmdUnspecified);, it says Microsoft C++ exception: _com_error at memory location and in the debug window there is _hr with value _hr : DB_E_ERRORSINCOMMAND One or more errors occurred during processing of command. TYPE: HRESULT
I also tried to execute Command, but I have the same result as Connection.
Should I change adCmdUnspecified into something or am I go wrong somewhere?
What is the solution? Thank you in advance.
//connections above
VARIANT vNameStringType;
_bstr_t InsertQuery(L"Insert Into TestTB(AccountID, Name) Values(#AccountID, #Name)");
hr = pCommand.CreateInstance(__uuidof(Command));
pCommand->ActiveConnection = pConnection;
pCommand->CommandText = InsertQuery;
pCommand->CommandType = adCmdText;
for (int i = 0; i < size; i++)
{
a[i].name;
a[i].login;
vIntegerType.vt = VT_I4;
vIntegerType.intVal = a[i].login;
vNameStringType.vt = VT_BSTR;
vNameStringType.bstrVal = _bstr_t(a[i].name);
int DataExistCounter = 0;
NameParam = pCommand->CreateParameter(_bstr_t("#Name"), adVarChar, adParamInput, 150, _bstr_t(vNameStringType));
pCommand->Parameters->Append(NameParam);
AccIDParam = pCommand->CreateParameter("#AccountID", adInteger, adParamInput, sizeof(int), vIntegerType);
pCommand->Parameters->Append(AccIDParam);
pRecordset->MoveFirst();
while (!pRecordset->EndOfFile)
{
valFieldNam = pRecordset->Fields->GetItem("Name")->Value;
valFieldAcc = pRecordset->Fields->GetItem("AccountID")->Value;
if (valFieldAcc == a[i].login)
{
DataExistCounter++;
}
pRecordset->MoveNext();
}
if (DataExistCounter > 0)
{
//update
}
else
{
pConnection->Execute(InsertQuery, NULL, adCmdUnspecified);
}
}
pRecordset->Close();
pConnection->Close();
CoUninitialize();

Not able to insert unsigned __int64 value in sql_variant data type column using OLE DB in c++

I am trying to insert a value of type unsigned __int64 in MS Sql Server using OLE DB with C++ for a column which has sql_variant data type column. Although for all other data type I am able to do so.
Code snippet:
HRESULT hrinit = CoInitialize(NULL);
Cvar_table table;
HRESULT hro = table.OpenAll();
table.m_ValueId = 1;
table.m_dwValueIdStatus = DBSTATUS_S_OK;
unsigned __int64 ui = 1234567;
VARIANT vt;// <- This is not OK! I can not insert it
vt.vt = VT_UI8;
vt.ullVal = ui;
unsigned int ui4 = 1234567;
VARIANT vt4; //<- This is OK! I can insert this.
vt4.vt = VT_UI4;
vt4.ullVal = ui4;
table.m_Value = vt;
table.m_dwValueStatus = DBSTATUS_S_OK;
HRESULT hr = table.Insert();
if (FAILED(hr))
{
_tprintf(_T("Insert failed: 0x%X\n"), hr);
}
table.CloseAll();
CoUninitialize();
return 0;
I wonder if sql_variant supports VT_UI8? Thanks in advance.

Calling OLAP BAPI from C++

I am trying to use SAP OLAP BAPI for a very simple task. I want to connect to a SAP BW server, send an MDX query, get the result and disconnect. While I seem to have no problems connecting and disconnecting from the server, sending a query and retrieving results seem to be rather non-trivial tasks that I am seeking help with.
According to the SAP documentation, I need to use MDDataSetBW object, by first creating the query object using CreateObject and then retrieving the results using GetAxisInfo and GetCellData.
Right now I am stuck at the very first step of just creating the query object. The documentation states that CreateObject has one import parameter CommandText and two export parameters DataSetID and Return. The problem is that according to SAP Documentation CommandText parameter is a table with a single column called LINE. So basically it's just an MDX query, with each line of the query being a value of the LINE column of each row of this table. The question is how do I pass it? Can anyone point me to a C++ example code that does something like this?
Here's my current prototype code:
#include "stdafx.h"
using namespace std;
RFC_HANDLE Logon()
{
RFC_CONNOPT_R3ONLY conn_options;
conn_options.hostname = SAP_LOGON::Hostname;
conn_options.sysnr = 0;
conn_options.gateway_host = nullptr;
conn_options.gateway_service = nullptr;
RFC_OPTIONS options;
options.mode = RFC_MODE_R3ONLY;
options.destination = SAP_LOGON::Destination;
options.client = SAP_LOGON::Client;
options.user = SAP_LOGON::User;
options.password = SAP_LOGON::Password;
options.language = SAP_LOGON::Language;
options.trace = 0;
options.connopt = &conn_options;
RFC_HANDLE hConn = RfcOpen(&options);
if (hConn == RFC_HANDLE_NULL)
ErrorHandler(_T("RfcOpen"));
return hConn;
}
void MakeStringParam(RFC_PARAMETER& param, rfc_char_t* name, rfc_char_t* buf, unsigned long size)
{
param.name = name;
param.nlen = (unsigned int)wcslen(name);
param.type = TYPC;
param.leng = size;
param.addr = &buf;
}
RFC_HANDLE WIN_DLL_EXPORT_FLAGS CreateQuery(RFC_HANDLE hConn, rfc_char_t* query)
{
rfc_char_t datasetID[256];
rfc_char_t ret[256];
RFC_PARAMETER exporting[3];
MakeStringParam(exporting[0], _T("DataSetID"), datasetID, 256);
MakeStringParam(exporting[1], _T("Return"), ret, 256);
exporting[2].name = nullptr;
// TODO: is it needed?
RFC_PARAMETER importing[2];
MakeStringParam(importing[0], _T("CommandText"), ret, 256);
importing[1].name = nullptr;
// TODO: put query into the table parameter
RFC_TABLE tables[2];
tables[0].name = _T("CommandText");
tables[1].name = nullptr;
rfc_char_t* ex = nullptr;
RFC_RC rc = RfcCallReceive(hConn, _T("BAPI_MDDATASETBW_CREATE_OBJECT"), exporting, importing, tables, &ex);
if (rc == RFC_OK)
{
// TODO: retrieve query handle here
RFC_HANDLE result = RFC_HANDLE_NULL;
return result;
}
return RFC_HANDLE_NULL;
}
int _tmain(int argc, _TCHAR* argv[])
{
RfcInit();
RFC_HANDLE hConn = Logon();
rfc_char_t* query = _T("\
SELECT\
{[Measures].[DA70CEZJ18267Q9RS4XFK7J32]} ON COLUMNS,\
{[0APO_LOCNO].[LEVEL01].AllMembers} ON ROWS\
FROM [0APO_C01/IDES_APO_04]");
RFC_HANDLE hQuery = CreateQuery(hConn, query);
// TODO: retrieve query results using
// - MDDataSetBW.GetAxisData
// - MDDataSetBW.GetAxisInfo
// - MDDataSetBW.GetCellData
RfcClose(hConn);
return 0;
}

Have successfully inserted blob data to SQLite database but can't get the data inserted

I use BLOB to insert an object to a SQLite databse. After the insertion, I can get the data with "SELECT" sentence and the data is correct, although the row of "TASK_HEAD" is "Empty" when browsing the database with "SQLite Database Browser".
However, if I destroy the object which has just been inserted, I can't get the correct data anymore, with the pointer "pHead" points to an address where the content of its "id" member is "铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪UG?" when read in VS2008 in debug mode.
Here is an example:
// user-defined data type
typedef std::string TASK_ID;
struct TASK_HEAD
{
TASK_ID id;
std::string userData;
int Size()
{
return (id.size() + userData.size()) * sizeof(TCHAR);
}
};
// when TEST_INSIDE is defined, pHead is invalid; but if undef it, I can get the "head" I just inserted
// and if the blob data is a string (when USING_STRING is defined), I can get the string inserted into the db even though the "test" string has been destroyed
void CDBWriter::WriteTestData()
{
// open db
sqlite3* db = NULL;
int nRet = sqlite3_open(DATABASE_NAME.c_str(), &db);
if (nRet != SQLITE_OK)
{
return;
}
if (db != NULL)
{
// create a table
std::string cmdCreate("CREATE TABLE IF NOT EXISTS testTable (id TEXT NOT NULL, TASK_HEAD BLOB, PRIMARY KEY(id));");
char* errMsg = NULL;
nRet = sqlite3_exec( db , cmdCreate.c_str() , 0 , 0 , &errMsg );
if( errMsg != NULL )
{
sqlite3_free( errMsg );
errMsg = NULL;
return;
}
//#define USING_STRING
#define TEST_INSIDE
#ifndef TEST_INSIDE
TASK_HEAD head;
#endif // TEST_INSIDE
// insert blob data
const TASK_ID newID(NewGUID()); // NewGUID returns string like this: "5811307F-7AA7-4C44-831F-774FC5832627"
string query = "INSERT OR REPLACE INTO testTable (id, TASK_HEAD) VALUES ('";
query += newID;
query += "', ?1);";
sqlite3_stmt* res = NULL;
nRet = sqlite3_prepare_v2(db, query.c_str(), query.length(), &res, 0);
{
#ifdef TEST_INSIDE
TASK_HEAD head;
#endif // TEST_INSIDE
head.id = newID;
#ifdef USING_STRING
std::string test("ewsjoafijdoaijeofsafsd");
nRet = sqlite3_bind_blob (res, 1, test.c_str(), test.size(), SQLITE_TRANSIENT);
#else
int nsizeHead = sizeof(head);
int nSizeHeadSt = sizeof(TASK_HEAD);
int sizeString = sizeof(std::string);
size_t nLen = newID.size();
//nRet = sqlite3_bind_blob (res, 1, &head, sizeof(head), SQLITE_TRANSIENT);
nRet = sqlite3_bind_blob (res, 1, &head, head.Size(), SQLITE_TRANSIENT);
#endif // USING_STRING
if (SQLITE_OK == nRet)
{
nRet = sqlite3_step(res);
}
if (nRet != SQLITE_OK && nRet != SQLITE_DONE)
{
return;
}
}
// get all columns in the database
query = "SELECT * FROM testTable;";
nRet = sqlite3_prepare_v2 (db, query.c_str(), query.length(), &res, 0);
if (SQLITE_OK == nRet)
{
while (SQLITE_ROW == sqlite3_step(res))
{
#ifdef USING_STRING
const char* pHead = (const char*)sqlite3_column_blob(res, 1);
#else
const TASK_HEAD *pHead = (const TASK_HEAD*)sqlite3_column_blob(res, 1);
#endif // USING_STRING
continue;
}
}
sqlite3_finalize(res);
sqlite3_close(db);
}
}
At first, I thought it might be the problem of bytes passed to sqlite3_bind_blob, so I get the bytes of the object with a stupid method, as you can see here (the size() function of TASK_HEAD), but that doesn't help.
Then I tried to use SQLITE_STATIC instead of SQLITE_TRANSIENT, still not working.
What's wrong?
Ps: I know it's a bad solution to insert an object to the db, and I just wanna know why I can't read back my data inserted into the db.
The content of userData is likely to be stored on the heap. Even if it's stored inside the std::string (for SSO) it still may use a pointer to itself internally, and so it won't work when you bitwise copy it to another place in memory (what you're doing is equivalent to a memcpy).
However, it doesn't matter why exactly it doesn't work, since it's just undefined behavior. Just don't "insert an object to the db" like this. Either serialize it using some serialization library and then insert it, or use two columns in the table, one for id and one for userData.
I think the problem is at:
nRet = sqlite3_bind_blob (res, 1, &head, head.Size(), SQLITE_TRANSIENT);
You cannot get the address of the TASK_HEAD structure and pass it to sqlite like this. To build a blob you need flat data, nothing with pointers and dynamic buffers like std::string objects.
You need to serialize the TASK_HEAD structure in a buffer before the binding operation.
For instance:
struct TASK_HEAD
{
TASK_ID id;
std::string userData;
std::string Data()
{
return id+userData;
}
int Size()
{
return (id.size() + userData.size()) * sizeof(TCHAR);
}
};
and:
nRet = sqlite3_bind_blob (res, 1, head.Data().c_str(), head.Size(), SQLITE_TRANSIENT);
Please note adding the fields to serialize as shown above is very poor (since this format cannot be unserialized). To deal with blobs, you need to find a good serialization library or format (protocol buffer, message pack, JSON, etc ...) or roll your own.
There is a second issue in your code at:
const TASK_HEAD *pHead = (const TASK_HEAD*)sqlite3_column_blob(res, 1);
This will not work, for a similar reason.

MySQL C++ query Access Violation

I have a DLL where I make a connection to a MySQL database. I have Open(), Close(), Update(), and Find() functions. The Update() functions inserts data into a table and this works just fine. The Find() function however is just doing a simple query against the same table. When I call the resultset getXX() function I'm getting an Access Violation error and I can't figure out why. What am I missing? Note the query is a view and not a direct table but I wouldn't think that would matter.
MT4_EXPFUNC int __stdcall Find(char* pair)
{
try
{
sql::Statement *stmt;
sql::ResultSet* res;
string p = pair;
string buysell = "";
string qry = "select * from forex.GPBUSD_CURRENT_PRICE";
stmt = _connection->createStatement();
res = stmt->executeQuery(qry);
// if we have a record it means we have a trade chance
if(res->next())
{
buysell = res->getString(1); // ACCESS VIOLATION ERROR HERE
}
// clean up
delete res;
delete stmt;
if(buysell == "SELL")
return 1;
else if(buysell == "BUY")
return 2;
else
return 0;
}
catch(sql::SQLException &e)
{
return -1;
}
}
have you considered if getString is a zero indexed method? Or if it's a null datatype your trying to access? or shoot just because res->next() works and doesn't crash, doesn't mean that res is a valid ptr.