I have the following code, and sql string in which my errors have been solved on another post.
Basically, this function tests whether a table exists or not.. That's it.
I'm posted the relevant section below.. For some reason, even if the table doesn't exist in the database, my function always tells me that the table exists?
Any clues as to what I've done wrong here.. Could it be the way I'm using the return value of sqlite3_get_table?
string sql_string = "SELECT name FROM sqlite_master WHERE type = 'table' AND name='test_table';";
// open database
dbase_return = sqlite3_open_v2(dbase_path.c_str(),&DBHANDLE,SQLITE_OPEN_READWRITE,NULL);
if(!dbase_return)
{
dbase_return_tbl = sqlite3_get_table(DBHANDLE,sql_string.c_str(),&result,&row,&column,&error_msg);
if(dbase_return_tbl==SQLITE_OK)
{
cout << " Table exists" << endl;
sqlite3_close(DBHANDLE);
return 1;
}
else
{
cout << "Table doesn't exists" << endl;
sqlite3_close(DBHANDLE);
return 0;
}
}
Related
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";
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.
In the following code for retrieving data via a SQL query from the db, is there a way I can replace row[0] with fieldname. I am only enclosing the relevant part of the code
MYSQL_RES *resptr;
MYSQL_ROW row;
while ( ( row = mysql_fetch_row(resptr)) != NULL )
{
for (int i=0;i<8;i++)
string key = row[0];
}
row[0] is the trans_date column. the code works fine as it is right now, but is there a way to assign key by using the fieldname vs. having to remember all the field numbers.
thanks!
You can retrieve field names by doing
field = mysql_fetch_field(resptr);
std::cout << field->name;
(Put in a while loop to loop through all field)
But you can't call row[fieldName]. What you can do though is define variables to map column names and numbers
int id = 0;
int trans_date = 1;
// Code happening here
std::cout << row[id] << " " << row[trans_date];
UPDATE: You could always do something like this (using STL's map):
map<string, int> columns;
int i = 0;
while(field = mysql_fetch_field(resptr)){
columns.insert(pair<string,int>(field->name, i++));
}
And then use row[columns["name"]];.
MySQL++ solves this problem. You can say things like:
string key = row["key"];
or by use of its SSQLS feature, this:
MyTableStructure foo = result[i];
cout << "The key is " << foo.key << endl;
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.
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.