Mysql.h 0 results after query - c++

I made this:
int querystate;
std::string pol;
std::string login;
std::cout << "login: ";
std::cin >> login;
pol = "select * from table where login = '" + login + "';";
querystate = mysql_query(conn, pol.c_str());
if (querystate != 0)
{
std::cout << mysql_error(conn);
}
res = mysql_store_result(conn);
while ((row = mysql_fetch_row(res)) != NULL)
{
std::cout << row[0] << " " << row[1] << " " << row[2];
}
It is possible to make something like this?
if (res == 0)
{
cout<<"there is 0 results";
}
I want to output text when query returns 0 results, for example:
there is no such login in the database.

First, your code is open to an SQL injection attack. You need to escape the login string using mysql_real_escape_string_quote(), eg:
std::string escapeStr(MYSQL *mysql, const std::string &str, char quoteChar)
{
std::string out((str.size()*2)+1, '\0');
unsigned long len = mysql_real_escape_string_quote(mysql, out.data(), str.c_str(), str.size(), quoteChar);
out.resize(len);
return out;
}
std::string pol = "select * from table where login = '" + escapeStr(conn, login, '\'') + "';";
Though, you really should be using a prepared statement instead, let MySQL handle the escaping for you.
Second, the mysql_query() documentation says:
To determine whether a statement returns a result set, call mysql_field_count(). See Section 5.4.23, “mysql_field_count()”.
Where the mysql_field_count() documentation says:
The normal use of this function is when mysql_store_result() returned NULL (and thus you have no result set pointer). In this case, you can call mysql_field_count() to determine whether mysql_store_result() should have produced a nonempty result. This enables the client program to take proper action without knowing whether the query was a SELECT (or SELECT-like) statement. The example shown here illustrates how this may be done.
See Section 3.6.8, “NULL mysql_store_result() Return After mysql_query() Success”.
And that last document says:
It is possible for mysql_store_result() to return NULL following a successful call to to the server using mysql_real_query() or mysql_query(). When this happens, it means one of the following conditions occurred:
There was a malloc() failure (for example, if the result set was too large).
The data could not be read (an error occurred on the connection).
The query returned no data (for example, it was an INSERT, UPDATE, or DELETE).
You can always check whether the statement should have produced a nonempty result by calling mysql_field_count(). If mysql_field_count() returns zero, the result is empty and the last query was a statement that does not return values (for example, an INSERT or a DELETE). If mysql_field_count() returns a nonzero value, the statement should have produced a nonempty result. See the description of the mysql_field_count() function for an example.
So, for example:
std::string login;
std::cout << "login: ";
std::cin >> login;
std::string pol = "select * from table where login = '" + escapeStr(conn, login, '\'') + "';";
if (mysql_query(conn, pol.c_str()) != 0)
{
std::cout << mysql_error(conn);
}
else if ((res = mysql_store_result(conn)) != NULL)
{
while ((row = mysql_fetch_row(res)) != NULL)
{
std::cout << row[0] << " " << row[1] << " " << row[2];
}
mysql_free_result(res);
}
else if (mysql_field_count(conn) == 0)
{
std::cout << "there are 0 results";
}
else
{
std::cout << mysql_error(conn);
}
Alternatively, the documentation also says:
An alternative is to replace the mysql_field_count(&mysql) call with mysql_errno(&mysql). In this case, you are checking directly for an error from mysql_store_result() rather than inferring from the value of mysql_field_count() whether the statement was a SELECT.
std::string login;
std::cout << "login: ";
std::cin >> login;
std::string pol = "select * from table where login = '" + escapeStr(conn, login, '\'') + "';";
if (mysql_query(conn, pol.c_str()) != 0)
{
std::cout << mysql_error(conn);
}
else if ((res = mysql_store_result(conn)) != NULL)
{
while ((row = mysql_fetch_row(res)) != NULL)
{
std::cout << row[0] << " " << row[1] << " " << row[2];
}
mysql_free_result(res);
}
else if (mysql_errno(conn) == 0)
{
std::cout << "there are 0 results";
}
else
{
std::cout << mysql_error(conn);
}

From the documentation available in this site https://dev.mysql.com/doc/c-api/5.7/en/mysql-fetch-row.html
When used after mysql_store_result(), mysql_fetch_row() returns NULL if there are no more rows to retrieve.
so use that to verify whether the data has rows or not. Since doing this once would have fetched a row already, you need to print them immediately before trying to get another row from the DB.
row = mysql_fetch_row(res)
if( row == NULL ) // This verifies whether data is NULL or not
cout << " There is no Results "<<endl
else {
do
{
std::cout << row[0] << " " << row[1] << " " << row[2];
}
while (row = mysql_fetch_row(res)) != NULL)
}

Related

How do I reuse SQLiteCpp SQLite::Statement?

SQLiteCpp is a open sourced library for operating sqlite database. Here's an example.
try
{
// Open a database file
SQLite::Database db("example.db3");
// Compile a SQL query, containing one parameter (index 1)
SQLite::Statement query(db, "SELECT * FROM test WHERE size > ?");
// Bind the integer value 6 to the first parameter of the SQL query
query.bind(1, 6);
// Loop to execute the query step by step, to get rows of result
while (query.executeStep())
{
// Demonstrate how to get some typed column value
int id = query.getColumn(0);
const char* value = query.getColumn(1);
int size = query.getColumn(2);
std::cout << "row: " << id << ", " << value << ", " << size << std::endl;
}
}
catch (std::exception& e)
{
std::cout << "exception: " << e.what() << std::endl;
}
Since the query is passed in the constructor of Statement SQLite::Statement query(db, "SELECT * FROM test WHERE size > ?");, how do I reuse it?
I didn't see a method accepts a string like query.setQuery("select * from table"). Do you know how do I reuse it?
If it bothers you that much you can just reassign it:
query = SQLite::Statement{db, "select * from table"};

How to retrieve columns using mysql++ or other library?

First, I am new to C++; now,I am trying to write a project to listen to any database change from MySQL binlog and do something. I chose a library called mysql-binlog-repliation, following its example codes, now I can track event in MySQL binlog, retrieve old values and new values. However, I can not retrieve columns, I want to know how to retrieve columns together with values, appreciate for any useful answers!
Below is part of my codes:
while (true) {
int result = binlog.wait_for_next_event(&event);
if (result == ERR_EOF)
break;
std::cout << "Found event of type " << event->get_event_type();
int event_type = event->get_event_type();
if (event_type == mysql::TABLE_MAP_EVENT) {
tmev = (mysql::Table_map_event *)event;
std::string tablename=tmev->table_name;
}
if (event_type == mysql::WRITE_ROWS_EVENT || event_type==mysql::UPDATE_ROWS_EVENT || event_type==mysql::DELETE_ROWS_EVENT) {
mysql::Row_event *row_event = (mysql::Row_event *)event;
mysql::Row_event_set rows(row_event, tmev);
mysql::Row_event_set::iterator itor = rows.begin();
do {
mysql::Row_of_fields fields = *itor;
mysql::Row_of_fields::iterator it = fields.begin();
// Here,fields represent values,I have no way to get columns
do {
std::string out;
converter.to(out, *it);
std::cout << "\t" << out;
} while (++it != fields.end());
} while (++itor != rows.end());
}
std::cout << std::endl;

missing data in popen call

my program compiles without error and appears to run through all of the steps correctly. It is supposed to make a php call and return data. tcpdump does show the request going out so popen is being executed, but the receiving party never updates.
The only discrepancy I can find, is that the command variable appears to be missing data.
# .trol.o
market max price is 0.00638671 at position 0
php coin.php 155 0.006387
0.00638672
the second line in the output is the command I am sending to popen
cout << command << endl; -> php coin.php 155 0.006387
that number is supposed to be the same as the one under it 0.00638672
The number 6 and the number 2 have been chopped off somehow.
How do I get the correct data into my popen command?
code:
void mngr(){
//vector defs
vector<std::string> buydat;
vector<std::string> markdat;
vector<std::string> pricedat;
vector<std::string> purchaseid;
vector<double> doublePdat;
vector<double> doubleMdat;
doublePdat.reserve(pricedat.size());
doubleMdat.reserve(markdat.size());
char buybuff[BUFSIZ];
char command[70];
char sendbuy[12];
buydat = getmyData();
markdat = getmarketbuyData();
//string match "Buy" and send results to new vector with pricedat.push_back()
for(int b = 2; b < buydat.size(); b+=7){
if ( buydat[b] == "Buy" ) {
pricedat.push_back(buydat[b+1]);
}
}
transform(pricedat.begin(), pricedat.end(), back_inserter(doublePdat), [](string const& val) {return stod(val);});
transform(markdat.begin(), markdat.end(), back_inserter(doubleMdat), [](string const& val) {return stod(val);});
auto biggestMy = std::max_element(std::begin(doublePdat), std::end(doublePdat));
std::cout << "my max price is " << *biggestMy << " at position " << std::distance(std::begin(doublePdat), biggestMy) << std::endl;
auto biggestMark = std::max_element(std::begin(doubleMdat), std::end(doubleMdat));
std::cout << "market max price is " << *biggestMark << " at position " << std::distance(std::begin(doubleMdat), biggestMark) << std::endl;
if (biggestMy > biggestMark){
cout << "Biggest is Mine!" << endl;
}
else if (biggestMy < biggestMark){
//cout << "Biggest is market!";
*biggestMark += 0.00000001;
sprintf(sendbuy,"%f",*biggestMark);
sprintf(command, "php coin.php 155 %s",sendbuy);
FILE *markbuy = popen(command, "r");
if (markbuy == NULL) perror ("Error opening file");
while(fgets(buybuff, sizeof(buybuff), markbuy) != NULL){
size_t h = strlen(buybuff);
//clean '\0' from fgets
if (h && buybuff[h - 1] == '\n') buybuff[h - 1] = '\0';
if (buybuff[0] != '\0') purchaseid.push_back(buybuff);
}
cout << command << endl;
cout << *biggestMark << endl;
}
}
I would try to use long float format instead of float as the type of biggestMark should be evaluated as iterator across doubles. I mean try to change sprintf(sendbuy,"%f",*biggestMark); to sprintf(sendbuy,"%lf",*biggestMark);. Hope this would help.

c++ mysql++ if query is empty code never executes, but it should

If query is empty code never executes. I tried this with multiple variations. Here is simple code.
mysqlpp::Query query = conn.query();
query << "SELECT * FROM users WHERE username= "
<< mysqlpp::quote_only << username
<< "AND password= "
<< mysqlpp::quote_only << password;
mysqlpp::StoreQueryResult res = query.store();
mysqlpp::StoreQueryResult::const_iterator it;
for (it = res.begin(); it != res.end(); ++it)
{
mysqlpp::Row row = *it;
if (!row.empty())
{
// user name and password match, log them in
std::cout << "You are logged" << std::endl;
// rest of code goes here
}
else if (row.empty()) // even just 'else' doesnt get executed
{
// no username or password that matches with user input
std::cout << "Wrong username or password" << std::endl;
// rest of code goes here
// this never get executed, and i have no idea why
}
}
How to check if row is empty? I tried almost anything i found in their reference manual, still nothing.

const char * changing value during loop

I have a function that iterates through a const char * and uses the character to add objects to an instance of std::map if it is one of series of recognized characters.
#define CHARSEQ const char*
void compile(CHARSEQ s) throw (BFCompilationError)
{
std::cout << "#Receive call " << s << std::endl;
for(int i = 0; s[i] != '\0'; i++)
{
if (std::string("<>-+.,[]").find_first_of(s[i]) == std::string::npos)
{
throw BFCompilationError("Unknown operator",*s,i);
}
std::cout << "#Compiling: " << s[i] << std::endl;
std::cout << "#address s " << (void*)s << std::endl;
std::cout << "#var s " << s << std::endl;
controlstack.top().push_back(opmap[s[i]]);
}
}
The character sequence passed is "++++++++++."
For the first three iterations, the print statements display the expected values of '+', '+', and '+', and the value of s continues to be "+++++++++++.". However, on the fourth iteration, s becomes mangled, producing bizarre values such as 'Ð', 'öê', 'cR ', 'œk' and many other character sequences. If the line that throws the exception is removed and the loop is allowed to continue, the value of s does not change after again.
Other functions have access to s but since this is not a multithreaded program I don't see why that would matter. I am not so much confused about why s is changing but why it only changes on the fourth iteration.
I have searched SO and the only post that seems at all relevant is this one but it still doesn't answer my question. (Research has been difficult because searching "const char* changing value" or similar terms just comes up with hundreds of posts about what part of is is const).
Lastly, I know I should probably be using std::string, which I will if no answers come forth, but I would still like to understand this behavior.
EDIT:
Here is the code that calls this function.
CHARSEQ text = load(s);
std::cout << "#Receive load " << text << std::endl;
try
{
compile(text);
}
catch(BFCompilationError& err)
{
std::cerr << "\nError in bf code: caught BFCompilationError #" << err.getIndex() << " in file " << s << ":\n";
std::cerr << text << '\n';
for(int i = 0; i < err.getIndex(); i++)
{
std::cerr << " ";
}
std::cerr << "^\n";
std::cerr << err.what() << err.getProblemChar() << std::endl;
return 1;
}
Where load is:
CHARSEQ load(CHARSEQ fname)
{
std::ifstream infile (fname);
std::string data(""), line;
if (infile.is_open())
{
while(infile.good())
{
std::getline(infile,line);
std::cout << "#loading: "<< line << '\n';
data += line;
}
infile.close();
}
else
{
std::cerr << "Error: unable to open file: " << fname << std::endl;
}
return std::trim(data).c_str();
}
and the file fname is ++++++++++. spread such that there is one character per line.
EDIT 2:
Here is an example of console output:
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: +
#loading: .
#Receive load ++++++++++.
#Receive call ++++++++++.
#Compiling: +
#address s 0x7513e4
#var s ++++++++++.
#Compiling: +
#address s 0x7513e4
#var s ++++++++++.
#Compiling: +
#address s 0x7513e4
#var s ++++++++++.
#Compiling:
#address s 0x7513e4
#var s ßu
Error in bf code: caught BFCompilationError #4 in file bf_src/Hello.txt:
ßu
^
Unknown operatorß
Your load function is flawed. The const char* pointer returned by c_str() is valid only until the underlying std::string object exists. But data is a local variable in load and is cleared after return. Its buffer is not overwritten by zeroes but left as it were as free memory. Therefore printing out the value immediately after returning is likely to work but your program may put new values there and the value pointed by your pointer will change.
I suggest to use std::string as the return value of load as a workaround.