Function returning MYSQL_ROW - c++

I'm working on a system using lots of MySQL queries and I'm running into some memory problems I'm pretty sure have to do with me not handling pointers right...
Basically, I've got something like this:
MYSQL_ROW function1() {
string query="SELECT * FROM table limit 1;";
MYSQL_ROW return_row;
mysql_init(&connection); // "connection" is a global variable
if (mysql_real_connect(&connection,HOST,USER,PASS,DB,0,NULL,0)){
if (mysql_query(&connection,query.c_str()))
cout << "Error: " << mysql_error(&connection);
else{
resp = mysql_store_result(&connection); //"resp" is also global
if (resp) return_row = mysql_fetch_row(resp);
mysql_free_result(resp);
}
mysql_close(&connection);
}else{
cout << "connection failed\n";
if (mysql_errno(&connection))
cout << "Error: " << mysql_errno(&connection) << " " << mysql_error(&connection);
}
return return_row;
}
And function2():
MYSQL_ROW function2(MYSQL_ROW row) {
string query = "select * from table2 where code = '" + string(row[2]) + "'";
MYSQL_ROW retorno;
mysql_init(&connection);
if (mysql_real_connect(&connection,HOST,USER,PASS,DB,0,NULL,0)){
if (mysql_query(&connection,query.c_str()))
cout << "Error: " << mysql_error(&conexao);
else{
// My "debugging" shows me at this point `row[2]` is already fubar
resp = mysql_store_result(&connection);
if (resp) return_row = mysql_fetch_row(resp);
mysql_free_result(resp);
}
mysql_close(&connection);
}else{
cout << "connection failed\n";
if (mysql_errno(&connection))
cout << "Error : " << mysql_errno(&connection) << " " << mysql_error(&connection);
}
return return_row;
}
And main() is an infinite loop basically like this:
int main( int argc, char* args[] ){
MYSQL_ROW row = NULL;
while (1) {
row = function1();
if(row != NULL) function2(row);
}
}
(variable and function names have been generalized to protect the innocent)
But after the 3rd or 4th call to function2, that only uses row for reading, row starts losing its value coming to a segfault error...
Anyone's got any ideas why? I'm not sure the amount of global variables in this code is any good, but I didn't design it and only got until tomorrow to fix and finish it, so workarounds are welcome!
Thanks!

Update: I misunderstood how mysql results are used. It looks like the row pointer array points to the results array which you free in function1() and then use it in function2() after it has been returned to the heap.
What you need to do is copy return_row[2] to a persistent string before freeing the results. Then pass that on to function2(). I see you doing something similar in function2() so you need to fix it there as well (though in your example you aren't doing anything with its return value).
Also, you are correct that free(row); is not the correct thing to do.

You should not be closing the connection or freeing the result set while you are processing a row returned by mysql_fetch_row.

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"};

My application is crashing using Do/While loop to parse table

I have 2 QCheckbox tables, each contains 11 elements.
I declare them as following in my class :
QCheckBox *sectionTable[10];
QCheckBox *postTable[10];
For each QCheckBox, I do this
QCheckBox* checkboxA = new QCheckBox("A");
sectionTable[0] = checkboxA;
Through my test method, I would like to return the content of each element of my QCheckbox tables.
To do so, I've done this test :
/** TEST() **/
void VGCCC::test()
{
sectionTable[0]->setText("A");
sectionTable[1]->setText("B");
sectionTable[2]->setText("C");
sectionTable[3]->setText("D");
postTable[0]->setText("E");
postTable[1]->setText("F");
postTable[2]->setText("G");
postTable[3]->setText("H");
int i=0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << sectionTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull());
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty());
}
My application is compiling, and also running. But when I call the test function, my application crash.
How can we explain this problem ?
I would like to notify that I get a result in my console. It seems my test is half working, but is crashing at the end of the 1st do/while loop, when I get out of my condition.
With regard to the 11 elements: QCheckBox *sectionTable[10]; defines only 10 slots (0 through 9) for elements.
int i=0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << sectionTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull());
Has the potential to reach past ten or eleven elements. Unless the terminating condition is found earlier, there is nothing to stop sectionTable[i] from trying to read sectionTable[11] to call its text method. If it manages to survive the call to the out-of-range sectionTable[11]->text(), it will then try calling sectionTable[11]->text().isNull(). Possibly this will be survivable as well and not be NULL. In this case sectionTable[12] will be tested. This will continue until the program hits really bad memory and crashes, a null is found, or pigs become the terror of the airways we all know they truly wish to be.
Note that i is not set back to 0 after this loop, so the first postTable to be inspected in the next loop will be at the same index as the last sectionTable.
So if sectionTable[5]->text().isNull() was NULL, postTable[5] will be the first postTable indexed and inspected.
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty());
This loop has the same error in the exit condition as the sectionTable loop.
I find out how to solve the problem. As said in the answer before (#user4581301), I didn't set back my iterator i to 0.
Also, to avoid the "out of range" crash, I put a second condition which is i<sizeof(sectionTable[i]);
This is my fonctional test function :
/** TEST() **/
void VGCCC::test()
{
int i = 0;
do
{
m_testTextEdit->insertPlainText(sectionTable[i]->text());
std::cout << "SECTION TABLE " << m_materialMap[sectionTable[i]].c_str() << "\n" << std::endl;
i++;
}
while(!sectionTable[i]->text().isNull() && i<sizeof(sectionTable[i]));
i = 0;
do
{
m_testTextEdit->insertPlainText(postTable[i]->text());
std::cout << "POST TABLE " << postTable[i]->text().toStdString() << "\n" << std::endl;
std::cout << "POST TABLE " << m_materialMap[postTable[i]].c_str() << "\n" << std::endl;
i++;
}
while(!postTable[i]->text().isEmpty() && i<sizeof(postTable[i]));
}

Binding and returning text data with sqlite3 and C++

I am trying to get back into programming for a personal project I would like to work on but I am having trouble figuring out the sqlite3 c/c++ api. I am modifying code snippets I found at various tutorials and I'm trying to get them return data and field names from a database. Here is the section of code that I am having difficulty with:
sqlite3 *db;
sqlite3_stmt *ppStmt;
int col_num;
char *zErrMsg = 0;
const char *zSql = "SELECT ?,? FROM basic_table";
string s = "Field1";
string t = "Field2";
rc = sqlite3_prepare_v2(db,zSql,-1,&ppStmt,0);
sqlite3_bind_text(ppStmt,1,s.c_str(),s.length(),SQLITE_TRANSIENT);
sqlite3_bind_text(ppStmt,2,t.c_str(),t.length(),SQLITE_TRANSIENT);
if(rc)
{
cerr << "SQL error: " << sqlite3_errmsg(db) << endl;
}
else
{
col_num = sqlite3_column_count(ppStmt);
do
{
rc = sqlite3_step(ppStmt);
switch(rc)
{
case SQLITE_DONE:
break;
case SQLITE_ROW:
for( int i=0; i<col_num; i++)
{
cout << sqlite3_column_name(ppStmt, i) << " " <<
sqlite3_column_text(ppStmt,i) << endl;
}
break;
default:
cerr << "Inside error " << sqlite3_errmsg(db) << endl;
break;
}
} while( rc==SQLITE_ROW );
sqlite3_finalize(ppStmt);
The column_name return the correct value but the data just comes back with a question mark. I can get the code to work by calling sqlite3_exec with a callback function but the documentation for sqlite3 recommends using sqlite3_prepare_v2, sqlite3_bind, sqlite3_step, and sqlite3_finalize instead of this method so I am just trying to see if I can get that method to work. Is there a simple error which I am making? Any suggestions would be appreciated.
The name of these columns is ?, because that is how they are written in the query.
The values of these columns are Field1 and Field2, because you told the database that you want to have these string values returned by the SELECT.
The database works as designed.
Parameters can be used only to replace the value of an expression; you cannot use them to replace identifiers such as column/table names.
You have to write the column names directly in the SQL statement:
const char *zSql = "SELECT Field1, Field2 FROM basic_table";

MySQL C++ connector MySQL_Prepared_Statement::getUpdateCount error

I'm using MySQL C++ connector version 1.1.0.
This is how my code looks like:
PreparedStatement *pStatement;
connection->setAutoCommit(false);
pStatement = connection->prepareStatement("UPDATE records "
"SET is_processed = ? "
"WHERE id = ?");
//LOOP BEGIN
pStatement->setInt(1, is_processed);
pStatement->setString(2, record_id);
pStatement->execute();
//LOOP END
int updated_records;
try
{
updated_records = pStatement->getUpdateCount();
}
catch(SQLException&e)
{
cout << "ERROR: " << e.what();
cout << " (MySQL error code: " << e.getErrorCode();
cout << ", SQLState: " << e.getSQLState() << ")" << endl;
}
connection->commit();
connection->setAutoCommit(true);
The exception is thrown with following output:
ERROR: MySQL_Prepared_Statement::getUpdateCount (MySQL error code: 0, SQLState: )
So it says totally nothing. What's wrong with getUpdateCount() function? Is there some way I can get more detailed error reporting level?
EDIT
Is there any other way to get updated rows count using mysql c++ connector?
I ran into this problem as well. I ended up taking a look at the source code. It appears that the source explicitly will throw an exception.
uint64_t
MySQL_Prepared_Statement::getUpdateCount()
{
checkClosed();
throw MethodNotImplementedException("MySQL_Prepared_Statement::getUpdateCount");
return 0; // fool compilers
}
I've finally found working solution:
int updated_records = 0;
//LOOP BEGIN
pStatement->setInt(1, is_processed);
pStatement->setString(2, record_id);
updated_records += pStatement->executeUpdate();
//LOOP END
cout << updated_records;
executeUpdate() return number of affected rows and it works without any error, so that's enough for me.
To clarify for others, because I was confused; do it like this:
pstmt = con->prepareStatement ("UPDATE localdata SET Val = ? WHERE ID = ?");
pstmt->setDouble (1, 7.77); // first "?"
pstmt->setInt (2, 0); // second "?"
pstmt->executeUpdate ();
The trick is setting the values according to their table type and order in the statement.

Corrupted mysql table, cause crash in mysql.h (c++)

i've created a very simple mysql class in c+, but when happen that mysql crash , indexes of tables become corrupted, and all my c++ programs crash too because seems that are unable to recognize corrupted table and allowing me to handle the issue ..
Q_RES = mysql_real_query(MY_mysql, tmp_query.c_str(), (unsigned int) tmp_query.size());
if (Q_RES != 0) {
if (Q_RES == CR_COMMANDS_OUT_OF_SYNC) cout << "errorquery : CR_COMMANDS_OUT_OF_SYNC " << endl;
if (Q_RES == CR_SERVER_GONE_ERROR) cout << "errorquery : CR_SERVER_GONE_ERROR " << endl;
if (Q_RES == CR_SERVER_LOST) cout << "errorquery : CR_SERVER_LOST " << endl;
LAST_ERROR = mysql_error(MY_mysql);
if (n_retrycount < n_retry_limit) { // RETRY!
n_retrycount++;
sleep(1);
cout << "SLEEP - query retry! " << endl;
ping();
return select_sql(tmp_query);
}
return false;
}
MY_result = mysql_store_result(MY_mysql);
B_stored_results = true;
cout << "b8" << endl;
LAST_affected_rows = (mysql_num_rows(MY_result) + 1); // coult return -1
cout << "b8-1" << endl;
the program terminate with a "segmentation fault" after doing the "b8" and before the "b8-1"
, Q_RES have no issue even if the table is corrupted.. i would like to know if there is a way to recognize that the table have problems and so then i can run a mysql repair or mysql check ..
thanks,
Francesco
You need to check the return value of mysql_store_result() - it might be NULL.
http://dev.mysql.com/doc/refman/5.0/en/mysql-store-result.html
mysql_store_result() returns a null
pointer if the statement didn't return
a result set (for example, if it was
an INSERT statement).
mysql_store_result() also returns a
null pointer if reading of the result
set failed. You can check whether an
error occurred by checking whether
mysql_error() returns a nonempty
string, mysql_errno() returns nonzero,
or mysql_field_count() returns zero.
It's probably not a problem with the database being corrupted.