I am trying to read a SQL Server table in C++ using a function like this..
CCommand<CDynamicAccessor>* Read(char* tblName)
{
wostringstream query;
query << "SELECT * FROM " << tblName;
return dataSource -> Query (query);
}
which calls this other function
CCommand<CDynamicAccessor>* Query(wostringstream& query)
{
HRESULT hr;
hr = _cmd.Open(_sess, _T(query.str().c_str()));
if (FAILED(hr))
{
std::wcout<<query.str().c_str() << "\n";
THROW_EXCEPTION("Command not executed.");
}
return &_cmd;
}
The problem is when I try to retrieve the column values using something like this
char* column20= (char*)cmd->GetValue("column20");
char* column21= (char*)cmd->GetValue("column21"); //Error
Because in the column20 I get the full string ex. "Value1"
But in the column21 I only get the first character ex. "V", when I should get "Value2"
Is there any limitation in size or something like that which do not allow me to retrieve the full string for column21?
If so, what is the best way to solve this issue?
Most probably the result is a wchar_t * string and you cast it to char *
Related
How can I insert record in Microsoft Access?
CString SqlString;
CString name="I want to add this variable in Table3";
SqlString = "INSERT INTO Table3 (Name,Numbers) VALUES (name,099)";
When I do it that way gives the following error:
Database error:Too few parameters.Expected 1.
This is a snippet from my own application:
BOOL CCommunityTalksApp::SetRecordForTalkNumber(int iTalkNumber, UINT uID, CString &rStrError)
{
CDatabase *pDatabase;
CString strSQL, strField;
BOOL bOK;
pDatabase = theApp.GetDatabase();
if(pDatabase != nullptr)
{
if (iTalkNumber == 9999)
strField = _T(" ");
else
strField.LoadString(uID);
strSQL.Format(_T("INSERT INTO [Public Talk Titles] ([Theme], [Category], [Talk Number]) VALUES ('%s', 'NS', %d)"), strField, iTalkNumber);
TRY
{
pDatabase->ExecuteSQL((LPCTSTR)strSQL);
bOK = TRUE;
}
CATCH(CDBException, Except)
{
rStrError = Except->m_strError;
bOK = FALSE;
}
END_CATCH
}
return bOK;
}
As you can see:
Use [ and ] to wrap the table and field names to address any issues with spaces.
Qualify the field names first — particularly if you are only populating certain field values.
Wrap the string values with single quotes.
So:
SqlString = "INSERT INTO Table3 (Name,Numbers) VALUES (name,099)";
Would be something like:
SqlString = "INSERT INTO [Table3] ([Name],[Numbers]) VALUES ('name',099)";
I appreciate that the square brackets are not needed for your table / field names though.
For example my inquiry(question?) in SQL is:
SELECT * from COMPANY where imie="John",surname="Wattson",age=31;
I use sqlite3_exec where one of the arguments is callback. I don't know if this record is in my table, and would like to know it using sqlite_exec.
What should I do?
Sorry for my English. :(
If you just want to see if a record exists in the table, then you could do it with sqlite3_exec() using a callback function like this:
int myCallback(void *pUser, int argc, char **colData, char **colNames) {
int *flag = (int*)pUser;
*flag = 1;
return 1;
}
This works because if there are no records matching the query, then the callback function is not called. By returning 1 instead of 0, we are telling SQLite that we don't want any more rows from the query results.
Then, in the function where you are making the db query:
std::string sql = "SELECT * FROM COMPANY WHERE imie='John' AND surname='Wattson' AND age=31;";
char *pSql = sql.c_str(); // char*'s are better for talking to SQLite, and prior to C++14,
// a std::string is not guaranteed to be sequential in memory,
// so 'sql[0]' may not work right
char *pError = NULL;
int fHasResult = 0;
// db is an already-opened sqlite3*
int result = sqlite3_exec(db, pSql, myCallback, &fHasResult, &pError);
if (result) {
cout<<"Error was: "<<pError;
free(pError);
}
if (fHasResult) {
cout<<"The row exists in the database.";
}
else {
cout<<"The row does not exist in the database.";
}
You could use EXISTS, your query should then look something like this;
SELECT EXISTS (SELECT * FROM COMPANY WHERE imie="John" AND surname="Wattson" AND age=31);
For another example you could take a look at this;
Valid query to check if row exists in SQLite3
I'm using pqlib with postgresql version 9.1.11
I have the following code
const char *spid = std::to_string(pid).c_str();
PGresult *res;
const char *paramValues[2] = {u->getID().c_str(), spid};
std::string table;
table = table.append("public.\"").append(Constants::USER_PATTERNS_TABLE).append("\"");
std::string param_name_pid = Constants::RELATION_TABLE_PATTERN_ID;
std::string param_name_uid = Constants::RELATION_TABLE_USER_ID;
std::string command = Constants::INSERT_COMMAND + table + " (" + param_name_uid + ", " + param_name_pid + ") VALUES ($1, $2::int)";
std::cout << "command: " << command << std::endl;
res = PQexecParams(conn, command.c_str(), 2, NULL, paramValues, NULL, NULL,0);
Where
INSERT_COMMAND = "INSERT INTO " (string)
USER_PATTERN_TABLE = "User_Patterns" (string)
RELATION_TABLE_PATTERN_ID = "pattern_id" (string)
RELATION_TABLE_USER_ID = "user_id" (string)
pid = an int
u->getID() = a string
conn = the connection to the db
The table "User_Patterns" is defined as
CREATE TABLE "User_Patterns"(
user_id TEXT references public."User" (id) ON UPDATE CASCADE ON DELETE CASCADE
,pattern_id BIGSERIAL references public."Pattern" (id) ON UPDATE CASCADE
,CONSTRAINT user_patterns_pkey PRIMARY KEY (user_id,pattern_id) -- explicit pk
)WITH (
OIDS=FALSE
);
I already have a user and a pattern loaded into their respective tables.
The command generated is :
INSERT INTO public."User_Patterns" (user_id, pattern_id) VALUES ($1, $2::int)
I also tried with $2, $2::bigint, $2::int4
The problem is:
I receive the error :
ERROR: invalid input syntax for integer: "public.""
I already use PQexecParams to store users and patterns, the only difference is that they all have text/xml fields (the only int field on patterns is a serial one and I don't store that value myself) but because the user_patterns is a relation table I need to store and int for the pattern_id.
I already read the docs for pqlib and saw the examples, both are useless.
The problem is in the lines:
const char *spid = std::to_string(pid).c_str();
const char *paramValues[2] = {u->getID().c_str(), spid};
std::to_string(pid) creates temporary string and .c_str() returns a pointer to an internal representation of this string, which is destroyed at the end of the line, resulting in a dead pointer. You may also see answer to the question
stringstream::str copy lifetime
I use mysql++ library to connect to my database. I've created a Connection and Query:
Connection conn(false);
conn.connect("database", "localhost", "user", "pass");
Query query = conn.query();
Then I can send a query to the database like:
query << "select name from my_table1, my_table2 where age=20"
But I'd like to send a number variable instead of 20. I tried to do that in that way:
std::stringstream ss; //create a stringstream
ss << my_number //add number to the stream
std::string number = ss.str();
query << "select name from my_table1, my_table2 where age="+number;
Unfortunately, it doesn't work.
My second problem is analogous. I create an QPixmap object (here QPixmap doesn't matter anyway) and i've to give the constructor a path to my image:
std:string name;
(...)
std::string path = "/home/root/img/"+name+".png"; //name is a variable string
QPixmap *tmp = new QPixmap(QString::fromUtf8(path.c_str())); //conversion from string to QString
query << "select name from my_table1, my_table2 where age="+number;
should be:
query << "select name from my_table1, my_table2 where age=" << number;
since + is not a valid C++ streams concatenation operator.
What's the problem with the QPixmap? Maybe that should be a separate question?
For your second issue I'd recommend changing it from this:
std:string name;
(...)
std::string path = "/home/root/img/"+name+".png"; //name is a variable string
To this:
const QString name;
...
const QString path = QString("/home/root/img/%1.png").arg(name);
....
QPixmap tmp(path);
I'm attempting to convert a soap query written for C# into a gSoap query in Visual C++.
The C# query adds an XML node's to the query call, in order to pass parameters to the query:
XmlNode queryOpts = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
queryOpts.InnerXml = "<DateInUtc>TRUE</DateInUtc>";
Here's the C# query, passing various args (some args are specified as XmlNode objects)
XmlNode nodeListItems = listService.GetListItems("Announcements", null, query, viewFields, null, queryOpts, null);
The C++ / gSoap query allows me to pass a query and response object:
listService.__ns10__GetListItems(&announcementQuery, &announcementResponse)
The query object has various properties that can be set that relate to the arguments in the C# call:
announcementQuery.listName
announcementQuery.query
announcementQuery.queryOptions
announcementQuery.viewFields
The first argument there is a string, no problem.
The query, queryOptions and viewFields are a bit confusing.
"query" is a class of type _ns2__GetListItems_query, and it has the following functions & members:
soap_default()
soap_get()
soap_in()
soap_out()
soap_put()
soap_serialize()
soap_type()
__any
__mixed
for query, queryOptions and viewFields, I'd simply like to specify an xml formatted string, like the C# code does, but I'm not sure how this is done.
Can someone cast some experience on this?
thanks!
I'm assuming you've already discovered the answer to this, but I'll post some notes for posterity.
Here's a simple C++ demo for sending and XML doc to a ASP.NET web method.
int _tmain(int argc, _TCHAR* argv[])
{
Service1SoapProxy proxy;
_WebServiceNS1__HelloWorld helloWorld;
_WebServiceNS1__HelloWorld_xml xml;
_WebServiceNS1__HelloWorldResponse response;
xml.__any = "<doc><x>hi</x></doc>";
helloWorld.xml = &xml;
int result = proxy.HelloWorld(&helloWorld, &response);
fprintf(stdout, "result: %i\n", result);
switch(result)
{
case SOAP_OK:
fprintf(stdout, "Response: %s\n", response.HelloWorldResult);
break;
default:
break;
}
return 0;
}
Here's the trivial web method in the .NET service:
[WebMethod]
public string HelloWorld(XmlNode xml)
{
return string.Format("Your XML: {0}", xml.OuterXml);
}
If everything works, you'll see "Response: hi" on your console.