Working with Visual Studio, Windows 7 and mysql.h library.
What I want to do is send a MySQL query like this:
mysql_query(conn, \"SELECT pass FROM us
here is an example:
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
/// ...
string name_value = "Leo Tolstoy";
ostringstream strstr;
strstr << "SELECT pass FROM users WHERE name='" << name_value << "'";
string str = strstr.str();
mysql_query(conn, str.c_str());
Use a prepared statement, which lets you parameterize values, similar to how functions let you parameterize variables in statement blocks. If using MySQL Connector/C++:
// use std::unique_ptr, boost::shared_ptr, or whatever is most appropriate for RAII
// Connector/C++ requires boost, so
std::unique_ptr<sql::Connection> db;
std::unique_ptr<sql::PreparedStatement> getPassword
std::unique_ptr<sql::ResultSet> result;
std::string name = "Nikolai Gogol";
std::string password;
...
getPassword = db->prepareStatement("SELECT pass FROM users WHERE name=? LIMIT 1");
getPassword->setString(1, name);
result = getPassword->execute();
if (result->first()) {
password = result->getString("pass");
} else {
// no result
...
}
// smart pointers will handle deleting the sql::* instances
Create classes to handle database access and wrap that in a method, and the rest of the application doesn't even need to know that a database is being used.
If you really want to use the old C API for some reason:
MYSQL *mysql;
...
const my_bool yes=1, no=0;
const char* getPassStmt = "SELECT password FROM users WHERE username=? LIMIT 1";
MYSQL_STMT *getPassword;
MYSQL_BIND getPassParams;
MYSQL_BIND result;
std::string name = "Nikolai Gogol";
std::string password;
if (! (getPassword = mysql_stmt_init(mysql))) {
// error: couldn't allocate space for statement
...
}
if (mysql_stmt_prepare(getPassword, getPassStmt, strlen(getPassStmt))) {
/* error preparing statement; handle error and
return early or throw an exception. RAII would make
this easier.
*/
...
} else {
unsigned long nameLength = name.size();
memset(&getPassParams, 0, sizeof(getPassParams));
getPassParams.buffer_type = MYSQL_TYPE_STRING;
getPassParams.buffer = (char*) name.c_str();
getPassParams.length = &nameLength;
if (mysql_stmt_bind_param(getPassword, &getPassParams)) {
/* error binding param */
...
} else if (mysql_stmt_execute(getPassword)) {
/* error executing query */
...
} else {
// for mysql_stmt_num_rows()
mysql_stmt_store_result(getPassword);
if (mysql_stmt_num_rows(getPassword)) {
unsigned long passwordLength=0;
memset(&result, 0, sizeof(result));
result.length = &passwordLength;
mysql_stmt_bind_result(getPassword, &result);
mysql_stmt_fetch(getPassword);
if (passwordLength > 0) {
result.buffer = new char[passwordLength+1];
memset(result.buffer, 0, passwordLength+1);
result.buffer_length = passwordLength+1;
if (mysql_stmt_fetch_column(getPassword, &result, 0, 0)) {
...
} else {
password = static_cast<const char*>(result.buffer);
}
}
} else {
// no result
cerr << "No user '" << name << "' found." << endl;
}
}
mysql_stmt_free_result(getPassword);
}
mysql_stmt_close(getPassword);
mysql_close(mysql);
As you see, Connector/C++ is simpler. It's also less error prone; I probably made more mistakes using the C API than Connector/C++.
See also:
Wouldn't you just build the query-string, using sprint or concatenating strings or whatever, so that by the time it gets to MySQL, MySQL just sees the SQL and has no idea where the constant came from? Or am I missing something?