MySQL C++ connector MySQL_Prepared_Statement::getUpdateCount error - c++

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.

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

Queries containing table variable fail in Nanodbc

I have a query that declares a table variable. It seems nanodbc cannot fetch data although the query works fine when directly executed on SQL server. Does it mean complicated queries are not supported by nanodbc?
Environment
nanodbc version: 2.14
DBMS name/version: MS SQL Server 2017
ODBC connection string:
OS and Compiler: Windows, Visual C++ 2019
CMake settings:
Actual behavior
sql queries containing table variables do not work.
Expected behavior
sql queries containing table variables should work.
Minimal Working Example
void show(nanodbc::result& results)
{
const short columns = results.columns();
long rows_displayed = 0;
cout << "\nDisplaying " << results.affected_rows() << " rows "
<< "(" << results.rowset_size() << " fetched at a time):" << endl;
// show the column names
cout << "row\t";
for(short i = 0; i < columns; ++i)
cout << results.column_name(i) << "\t";
cout << endl;
// show the column data for each row
while(results.next())
{
cout << rows_displayed++ << "\t";
for(short col = 0; col < columns; ++col)
cout << "(" << results.get<string>(col, "null") << ")\t";
cout << endl;
}
}
nanodbc::connection db_conn_ = nanodbc::connection(db_conn_string_);
execute(db_conn_, NANODBC_TEXT("DROP TABLE IF EXISTS research.dbo.nanodbc_test"));
execute(db_conn_, NANODBC_TEXT("CREATE TABLE research.dbo.nanodbc_test(Name varchar(20), Age int)"));
execute(db_conn_, NANODBC_TEXT("INSERT INTO research.dbo.nanodbc_test(Name, Age) VALUES('Bar', 20)"));
execute(db_conn_, NANODBC_TEXT("INSERT INTO research.dbo.nanodbc_test(Name, Age) VALUES('Foo', 30)"));
nanodbc::result result_working = execute( db_conn_, NANODBC_TEXT("select * from research.dbo.nanodbc_test"));
show(result_working);
//The following query does not return valid result, result_not_working contains 0 observations.
nanodbc::result result_not_working = execute(
db_conn_,
NANODBC_TEXT(
"declare #names table(n varchar(20) not null primary key);"
" insert into #names select * from string_split('Bar,Foo', ',');"
" select[Name], [Age]"
" from research.dbo.nanodbc_test where Age in(20, 30)"
" and [Name] in(select n from #names)"
)
);
show(result_not_working);
The question above is solved by adding 'set nocount on' at the beginning of the query suggested by David and Dan mentioned below.
What I am trying to solve is actually a bit more complicated. I want to run a parameterized query.
string query = NANODBC_TEXT(
"set nocount on"
" declare #names table(n varchar(20) not null primary key);"
" insert into #names select * from string_split(?, ',');"
" select[Name], [Age]"
" from research.dbo.nanodbc_test where Age in(20, 30)"
" and [Name] in(select n from #names)"
);
nanodbc::statement statement = nanodbc::statement(db_conn__);
prepare(statement, query);
string names = "Bar,Foo";
//The error happens when I try to bind a string parameter.
statement.bind(0, names.c_str());
Can someone help on this? Thanks.

Assert "id < 0" failed in Qt ActiveX

I make a program using Microsoft Access 2010 ActiveX (COM) to display references of a project (.adp file):
Access::Application* app = new Access::Application(nullptr);
app->SetVisible(true);
app->OpenAccessProject("E:\\solulog_dev\\SoluTools\\app\\test\\sources\\utilitaires\\liste_aide.adp", true);
int nb_ref = app->References()->Count();
qDebug().nospace() << nb_ref << " references";
for(int ref_num = 1; ref_num <= nb_ref; ref_num++)
{
Access::Reference* ref = app->References()->Item(ref_num);
qDebug().nospace() << "Reference #" << ref_num << " : " << ref->Name() << " (" << ref->Guid() << ") : " << ref->FullPath();
}
app->CloseCurrentDatabase();
app->Quit();
But at execution, I get the right number of references (5 in this case), but any call to any property of any reference get the same error:
Debug Error!
Program: c:\Qt\5.11.1\msvc2015\bin\Qt5Cored.dll
Module: 5.11.1
File: qaxbase.cpp
Line: 3763
ASSERT: "id < 0" in file qaxbase.cpp, line 3763
It seems to failed when try accessing property through QMetaObject.
I also get a warning followed by an error on each call to "References" object. The code works (I get the right number of references), but maybe it's related:
CoCreateInstance failure (Classe non enregistrée)
QAxBase::setControl: requested control {eb106214-9c89-11cf-a2b3-00a0c90542ff} could not be instantiated
This CLSID is correctly registered and reference "Microsoft.Office.Interop.Access.ReferencesClass" as expected
Anyone can help me with this assert ?
I tried the exact same code but using QAxObject directly, not through C++ namespace generated using dumpcpp :
QAxObject* app = new QAxObject("Access.Application", nullptr);
app->setProperty("Visible", true);
app->dynamicCall("OpenAccessProject(QString, bool)", "E:\\solulog_dev\\SoluTools\\app\\test\\sources\\utilitaires\\liste_aide.adp");
QAxObject* references = app->querySubObject("References");
int nb_ref = references->property("Count").toInt();
qDebug().nospace() << nb_ref << " références";
for(int ref_num = 1; ref_num <= nb_ref; ref_num++)
{
QAxObject* reference = references->querySubObject("Item(QVariant)", ref_num);
qDebug().nospace() << "Reference #" << ref_num << " : " << reference->property("Name").toString() << " (" << reference->property("Guid").toString() << ") : " << reference->property("FullPath").toString();
}
app->dynamicCall("CloseCurrentDatabase()");
app->dynamicCall("Quit()");
delete app;
And this time, all works perfectly. Not error about bad instantiation and I get values for each reference... So I presume it is a dumpcpp error. Should I report this problem to Qt ?

Function returning MYSQL_ROW

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.

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.