C++ and MySQL - how to include variable in my query? - c++

I think I may be missing something really obvious here, but I have been struggling for way too long on this and my C++ is way rusty (10yrs+)
The code below works fine, but I need to be able to pass a variable into the query for lname. If I build the query in a string or char array I get an error that it is not compatible with parameter type of SQLWCHAR*
I know the code below is vulnerable to sql injection, but this is a one time hit on an isolated system, so I am really looking for simplicity more than anything else...
SQLHENV env;
SQLHDBC dbc;
SQLHSTMT sql_hStmt;
SQLRETURN ret;
SQLWCHAR outstr[1024];
SQLSMALLINT outstrlen;
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
ret = SQLDriverConnect(dbc, NULL, L"DSN=myDSN", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &sql_hStmt);
SQLWCHAR* SQL = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, SQL, SQL_NTS);
SQLFetch(sql_hStmt);

There are two problems here, one is constructing a string containing the query you want, the other is passing that string as an argument to the function.
My recommendation is to stay as "C++" as possible until you reach these C boundaries. So we should use std::wstring for the string processing up until the point where it needs to be a C-style string:
std::wstring statementText = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, const_cast<SQLWCHAR*>(statementText.c_str()), SQL_NTS);
The c_str() member function returns a pointer to a null-terminated array (i.e., a C-style string), but this pointer has the type const wchar_t*; that is, the contents of this C-style string cannot be modified.
This is a problem because SQLWCHAR* is just wchar_t*; it doesn't make any promise to leave the data alone. That is why I included the const_cast, to remove the const from the c_str() value.
This is not something you generally want to do. const_cast is arguably the scariest cast because you directly open up the door to undefined behavior, as it's UB to modify a const object:
const int x = 0;
const int* p = &x; // anyone using this pointer can't modify x
int* bad = const_cast<int*>(p); // but this one is not so good
*bad = 5; // undefined behavior
The reason it's okay here, though, is that SQLExecDirect doesn't actually modify the string it's passed; it's simply an implementation error that const isn't used, so us taking that away is okay. (This lack of const mistake is very common in C.)
If you really need a buffer that can be modified, then starting in the current version of C++ (C++11) you can do this safely:
std::wstring statementText = L"select * from DB.employees where lname='Smith'";
ret = SQLExecDirect(sql_hStmt, &statementText[0], SQL_NTS);
We're taking the address of the first element, which itself is in a null-terminated array; another C-style string. This time, though, we have a modifiable array; the type already matches.
(The reason I make note this is okay in C++11 is that technically in the previous version, C++03, this behavior wasn't guaranteed. It was actually intended to be, but an error in wording in the standard made it not so. To be practical, you're fine either way.)
Whichever one you want to use is up to you. Some will argue to just use &str[0] all the time so we definitely have no UB, I would argue to document your intent and belief that the function doesn't modify the string and cast away const but ultimately operate in a const mindset. If something bad happens it's easy to relax away from const than it is to wish you had put it on.
One important thing to note is that all these returned pointers (either str.c_str() or &str[0]) are only good as long as the str object itself is alive and not modified. This is bad:
const wchar_t* get_query()
{
std::wstring result = /* build query */;
// oops, this pointer stops being meaningful when result stops existing!
return result.c_str();
}
With that all out of the way, building up these strings is easy. We have std::wstringstream:
std::wstringstream ss;
ss << "this is basically an expanding buffer that accepts anything std::wcout will";
ss << std::endl;
ss << "this includes integers " << 5 << " and other stream-insertable types";
So you probably want something like this:
std::wstring build_query(const std::wstring& name)
{
// you can provide a starting string
std::wstringstream result(L"select * from DB.employees where lname=");
result << "\'" << name << "\'";
return result.str(); // this captures the buffer as a C++ string
}
// Remember, this would be bad!
//
// SQLWCHAR* SQL = const_cast<SQLWCHAR*>(build_query(L"Smith").c_str());
//
// Because the C++ string returned by build_query is temporary;
// it stops existing at the end of this full expression,
// so SQL would be a bad pointer. This is right:
std::wstring SQL = build_query(L"Smith");
ret = SQLExecDirect(sql_hStmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS);
Hope that helps.
Also, I would avoid using all-upper identifiers except for macros, because such names are overwhelmingly expected to be macros by people reading C++ code. Additionally, I've used C++-style casts in my example code; you should do the same. The C-style cast ((type)value) is simply too powerful to be safe.

I suggest you PREPARE a paramererized query string. See here
If you simply concatenate strings to build a new query each time, you may be leaving your site open to an SQL injection attack

You can simply do it by :
You can do it by
int var = 10;
string str = to_string(var);
string requete="INSERT INTO stat(temps) VALUES (\"";
requete += str;
requete += "\")";
mysql_query(&mysql,requete.c_str());
just specify in mySql that the field has a type of int , double , float etc.

Thank you to The Beast. If you are recording two or more data, it can be used as follows.
int state;
string mesafe = to_string(getdata1);
string aci = to_string(getdata2);
string query = "INSERT INTO tarama (mesafe,aci) VALUES (\"";
query += mesafe;
query += "\",\"";
query += aci;
query += "\")";
qstate = mysql_query(conn, query.c_str());
I couldn't get over this problem for days. Now the problem is solved.

Related

Why std::string makes WSAGetLastError returning zero?

Someday. I wrote Socket wrapper class like Python built-in socket library for C++ (Visual Studio 2015)
All functions are working very well. However, I found some functions I wrotten has a problem.
After using std::string's method like .size(), .clear(), WSAGetLastError() always return zero.
std::string str = "Hello, world";
size_t recvsz = ::send(socket, str.c_str(), str.size(), 0);
// Why always return zero after using std::string's methods?
int err = ::WSAGetLastError();
Therfore, I can't know socket states, socket is dead, or socket is still waiting for receiving data.
So, I used a method storing WSAGetLastError() returning value before std::string's methods and then restoring it using WSASetLastError().
std::string str = "Hello, world";
// Before using std::string's methods
int err = ::WSAGetLastError();
size_t recvsz = ::send(socket, str.c_str(), str.size(), 0);
// Restore error value after std::string's methods
::WSASetLastError(err);
Is it correct way I used? or why std::string makes last error returing zero?
edited: wow... I mistake.. :(. I use ::send not ::recv. sorry for confusing you
SOCKET socket;
char buf[100] = {0x00,};
std::string data, temp_buf;
ssize_t recvsz = ::recv(socket, buf, 99, 0);
// When err has proper error code before std::string methods
// It just for a test
// int err = ::WSAGetLastError();
temp_buf = buf;
data += buf;
int err = WSAGetLastError(); // Always return zero!
Because you committed a gross indiscretion by writing into read-only memory that you don't own. In short, you blatted your computer's memory and now your program won't work predictably.
With a compliant C++11 compiler, you could do:
ssize_t recvsz = ::recv(socket, &str[0], str.size(), 0);
That's because &str[0] is a pointer to the actual string buffer (in a non-const context), and because from C++11 that data is guaranteed to be stored
contiguously. Technically, before then, not so much (though in practice it basically always is).
Otherwise you're going to have to allocate a little char[] buffer of your own, into which to receive data. You can just give it automatic storage duration with practically no cost, unless you're on a embedded system with tight resource constraints (but then you wouldn't be using string anyway).
By the way, be careful of your return types: size_t is unsigned. recv returns a ssize_t which is signed and may be negative to indicate an error condition.
const size_t BUF_SIZE = 256;
char buf[BUF_SIZE];
ssize_t recvsz = ::recv(socket, &buf[0], BUF_SIZE, 0);
if (recvsz < 0) {
// ... handling
}
// Now, optionally:
std::string str(buf, recvsz);
Now, with all that fixed, the answer is that the "last error" is permitted to be changed even by a successful operation. So, yes, you'll have to save then re-set a previous "last error" value if you want it to be retained. This does seem to be of dubious value — why do you not handle the error where it is generated? Carrying on after causing an error seems like a bad way to do business.
You should not write to the internal buffer of std::string this way. It is managed by the object and you must use functions like append() or assign() to update it, so the string can track its current content and length.
Moreover, c_str() returns const char* pointer and you cannot write to such memory.
If you are sure, that you will always write the correct amount of bytes (so the size data written and the actual length of data stored internally will match), you can use operator[] to get the reference to a particular character inside the string (presumably, the first one in your case) and use its address as the target buffer.
As #AndyG noticed in his comment, C++ 17 introduced std::basic_string::data() which also returns pointer to the actual buffer.
Your code should take one of the following forms:
size_t recvsz = ::recv(socket, &str[0], str.size(), 0);
size_t recvsz = ::recv(socket, str.data(), str.size(), 0); // C++ 17, str must not be const

Loss of data while building a std::string from const char * or LPCSTR

I have a Function which returns a LPSTR/const char * and I need to convert it to a std::string. This is how I am doing it.
std::string szStr(foo(1));
It works just fine in all the cases just when foo returns a 32 characters long string it fails. With this approach I get "". So I thought it had to do something with the length. So I changed it a bit.
std::string szStr(foo(1) , 32);
This gives me "0"
Then I tried another tedious method
const char * cstr_a = foo(1);
const char * cstr_b = foo(2);
size_t ln_a = strlen(cstr_a);
size_t ln_b = strlen(cstr_b);
std::string szStr_a( cstr_a , ln_a );
std::string szStr_b( cstr_b , ln_b );
But strangely enough in this method both the pointers are getting the same value, viz foo(1) should return abc and foo(2) should return xyz. But here cstr_a is first getting abc but the moment cstr_b gets xyz, the value of both cstr_a and cstr_b becomes xyz. I am dazed and confused with this.
And yes, I cannot use std::wstring.
What is foo?
foo is basically reading a value from the registry and returning it as a LPSTR. Now one the value in the registry which I need to read is a MD5 hashed string (32 charecters) That's where it fails.
The Actual Foo function:
LPCSTR CRegistryOperation::GetRegValue(HKEY hHeadKey, LPCSTR szPath, LPCSTR szValue)
{
HKEY hKey;
CHAR szBuff[255] = ("");
DWORD dwBufSize = 255;
::RegOpenKeyEx(hHeadKey, (LPCSTR)szPath, 0, KEY_READ, &hKey);
::RegQueryValueEx(hKey, (LPCSTR)szValue, NULL, 0, (LPBYTE)szBuff, &dwBufSize);
::RegCloseKey(hKey);
LPCSTR cstr(szBuff);
return cstr;
}
The Original cast code:
StrResultMap RegValues;
std::string lid(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "LicenseID"));
std::string mid(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "MachineID"), 32);
std::string vtill(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "ValidTill"));
std::string adate(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "ActivateDT"));
std::string lupdate(CRegistryOperation::GetRegValue(HKEY_CURRENT_USER, REG_KEY_HKCU_PATH, "LastUpdate"));
RegValues["license_id"] = lid;
RegValues["machine_id"] = mid;
RegValues["valid_till"] = vtill;
RegValues["activation_date"] = adate;
RegValues["last_updated"] = lupdate;
Kindly help me get over it.
Thanks.
As a complement to Nordic Mainframe's anwser, there are 3 common ways to return a buffer from a C or C++ function :
use a static buffer - simple and nice until you have re-entrancy problems (multiple threads or recursivity)
pass the buffer as an input parameter, and simply return the number of characters written to it - ok if the size of buffer is really a constant
malloc the buffer in the function (it is in the heap and not in the stack) and document in flashing red that it must be freed by caller
But as you tagged your question as C++, you could create the std::string in the function and return it. C++ functions are allowed to return std::string because the different operators (copy constructor, affectation, ...) take care automatically of the allocation problem.
You can avoid returning a pointer to a buffer which has gone out of scope by returning a std::string directly.
std::string CRegistryOperation::GetRegValue(HKEY hHeadKey, LPCSTR szPath, LPCSTR szValue)
{
HKEY hKey = 0;
CHAR szBuff[255] = { 0 };
DWORD dwBufSize = sizeof(szBuf);
if (::RegOpenKeyEx(hHeadKey, (LPCSTR)szPath, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
::RegQueryValueEx(hKey, (LPCSTR)szValue, NULL, 0, (LPBYTE)szBuff, &dwBufSize);
::RegCloseKey(hKey);
}
return std::string(szBuf);
}
The GetRegValue function returns a pointer to a buffer in GetRegValue's stack frame. This does not work: after GetRegValue terminates the pointer cstr points to undefined values somewhere in the Stack. Try to make szBuff static and see if that helps.
LPCSTR CRegistryOperation::GetRegValue(HKEY hHeadKey, LPCSTR szPath, LPCSTR szValue)
{
HKEY hKey;
//Here:
static CHAR szBuff[255] = ("");
szBuff[0]=0;
DWORD dwBufSize = 255;
::RegOpenKeyEx(hHeadKey, (LPCSTR)szPath, 0, KEY_READ, &hKey);
::RegQueryValueEx(hKey, (LPCSTR)szValue, NULL, 0, (LPBYTE)szBuff, &dwBufSize);
::RegCloseKey(hKey);
LPCSTR cstr(szBuff);
return cstr;
}
UPDATE: I did not mandate to return std::string, or pass a buffer in, because that would change the interface. Returning a pointer to a static buffer is a common idiom and mostly unproblematic if the lifetime of the returned pointer value is limited to a few scopes (Like for building a std::string from the buffer value).
Multithreading isn't really an issue aynmore, because almost every compiler now has some form of thread local storage support right in the language. __declspec(thread) static CHAR szBuff[255] = (""); for example, should work for Microsoft compilers, __thread for gcc. C++11 even has a new storage class specifier for this (thread_local). You shouldn't call GetRegValue from a signal handler though, but that's OK - you can't do too much there anyway (for example allocate memory from the heap!).
UPDATE: Commenters argue, that I should not suggest this, because the pointer to the static buffer will point to invalid data when GetRegValue is called again. While this is obviously true, I think it is wrong to make an argument from that. Why? Look at these examples:
A pointer returned from strdup() is valid until free()
A pointer to something created with new is valid until deleted.
A const char * returned from string::c_str() is valid as long as the string is not modified.
A std::vector iterator is invalid, if an element from the std::vector is erased.
A std::list iterator is still valid, if an element from the std::vector is erased, unless it points to the erased element.
A pointer returned from GetRegValue is valid until GetRegValue is called again.
a std::ifstream is valid when,..you know, good(), fail() and so on.
There is no point in saying, "look, the thing gets invalid when you are not careful enought", because programming is not about being careless. We are handling objects, which have conditions under which they are valid or not and if an object has well defined conditions under which it is valid or not, then we can write programs with well defined behaviour. Returning a pointer to a static buffer (that is thread-local) has a well defined meaning and a developer can use this to write a well defined program. Unless said developer is negligent or too lazy to read the documentation of the routine of course.

Returning a constant char pointer yields an error

I am new to C++, and haven't quite grasped all the concepts yet, so i am perplexed at why this function does not work. I am currently not at home, so i cannot post the compiler error just yet, i will do it as soon as i get home.
Here is the function.
const char * ConvertToChar(std::string input1, std::string input2) {
// Create a string that you want converted
std::stringstream ss;
// Streams the two strings together
ss << input1 << input2;
// outputs it into a string
std::string msg = ss.str();
//Creating the character the string will go in; be sure it is large enough so you don't overflow the array
cont char * cstr[80];
//Copies the string into the char array. Thus allowing it to be used elsewhere.
strcpy(cstr, msg.c_str());
return * cstr;
}
It is made to concatenate and convert two strings together to return a const char *. That is because the function i want to use it with requires a const char pointer to be passed through.
The code returns a pointer to a local (stack) variable. When the caller gets this pointer that local variable doesn't exist any more. This is often called dangling reference.
If you want to convert std::string to a c-style string use std::string::c_str().
So, to concatenate two strings and get a c-style string do:
std::string input1 = ...;
std::string input2 = ...;
// concatenate
std::string s = input1 + input2;
// get a c-style string
char const* cstr = s.c_str();
// cstr becomes invalid when s is changed or destroyed
Without knowing what the error is, it's hard to say, but this
line:
const char* cstr[80];
seems wrong: it creates an array of 80 pointers; when it
implicitly converts to a pointer, the type will be char
const**, which should give an error when it is passed as an
argument to strcpy, and the dereference in the return
statement is the same as if you wrote cstr[0], and returns the
first pointer in the array—since the contents of the array
have never been initialized, this is undefined behavior.
Before you go any further, you have to define what the function
should return—not only its type, but where the pointed to
memory will reside. There are three possible solutions to this:
Use a local static for the buffer:
This solution was
frequently used in early C, and is still present in a number of
functions in the C library. It has two major defects: 1)
successive calls will overwrite the results, so the client code
must make its own copy before calling the function again, and 2)
it isn't thread safe. (The second issue can be avoided by using
thread local storage.) In cases like yours, it also has the
problem that the buffer must be big enough for the data, which
probably requires dynamic allocation, which adds to the
complexity.
Return a pointer to dynamically allocated memory:
This works well in theory, but requires the client code to free
the memory. This must be rigorously documented, and is
extremely error prone.
Require the client code to provide the buffer:
This is probably the best solution in modern code, but it does
mean that you need extra parameters for the address and the
length of the buffer.
In addition to this: there's no need to use std::ostringstream
if all you're doing is concatenating; just add the two strings.
Whatever solution you use, verify that the results will fit.

Converting sqlite result to std::string in C++

Im querying a sqlite db, but i need to convert the result (a TEXT attribute) to a C++ std::string. I feel like this should not be hard to accomplish, but im having trouble.
sqlite3_open("sqlite.db", &db);
std::string str = "SELECT something FROM table";
sqlite3_prepare_v2(db,
str.c_str(),
-1,
&m_statement,
0);
sqlite3_step(m_statement);
// OBS: 3rd party printf, cannot use std::cout in this environment
printf("Result1: %s",sqlite3_column_text(m_statement,0)); // OK! Result is printed
string try1 = string(
reinterpret_cast<const char*>(sqlite3_column_text(m_statement,0)));
printf("Result2: %s",try1); // null
stringstream ss;
ss << sqlite3_column_text(m_statement,0);
printf("Result3: %s",ss.str()); // null
Your problem isn't related to sqlite. When you use %s with printf, printf expects a char * NOT a std::string.
For example change this:
printf("Result2: %s",try1); // null
to
printf("Result2: %s",try1.c_str());
and see what happens.
C++ has two primary ways of implementing strings. The legacy C string (char*) and the std::string class found in the C++ standard library. If you deal with C APIs, you'll be dealing mostly with the former. printf and sqlite* are both from C APIs, so expect to deal with char*.
The problem is not with sqlite3_column_text.
printf format specifier %s expects a C string (char pointer).
As printf can't inspect what values are passed on the stack, so it has to trust the format specifier. Because the format specifier is %s, it reads an argument as it was a char pointer (it's not), but by coincidence, it's printing the wrong result, rather than crashing.
std::string exposes a function that gets you a read-only corresponding C string, so, for example, your the second case will be:
// Get a C string from std::string
printf("Result2: %s", try1.c_str());

Converting std::wstring to SQLWCHAR *

I have a C++ program that is dynamically creating a query string which will then be passed to a SQLExecDirect call to connect to a database using ODBC. I'm having trouble passing the variable from one function to another, so I think I must be missing something basic?
In the ConstructQuery function (which returns type SQLWCHAR *), I have:
std::wstring test = L"test string"; //This test string will actually be several concatenated strings
SQLWCHAR *statement = (SQLWCHAR *)test.c_str();
std::wcout << statement;
return statement;
This prints the statement variable as expected. But when I pass the variable to my main function like this:
SQLStatement = ConstructQuery(SQLStatement);
std::wcout << SQLStatement;
I get no output.
If, instead of statement = (SQLWCHAR *)test.c_str();
I use: statement = L"test string";
The variable passes fine, but then I am not able to dynamically create the "test string" query in the earlier part of the function.
I was having a hard time finding out much about SQLWCHAR. I'm guessing that I may be converting std::wstring to SQLWCHAR * incorrectly? Another option would be to rewrite the function so that all of the wstring are SQLWCHAR * and do the concatenation that way - but I'm not sure that's possible and even if it was I don't think it's preferred?
You are returning a pointer to a local variable that goes out of scope at the end of the function ConstructQuery. It might be easiest to return a std::wstring by value and then work from there.