PDA

View Full Version : QSqlQuery crash in destructor



seim
20th January 2010, 21:17
Hello friends,
I was testing QtSql with ODBC driver, ODBC manager unixODBC and Easysoft ODBC->MSSQL driver and got some really strange behavior with this example:

{
QSqlQuery query;
query.prepare("{call proc03test(?);}");
// proc03test is mssql stored procedure having 1 output integer parameter
query.bindValue(0, 1, QSql::Out);
bool result = query.exec();
qDebug() << "ID = " << query.boundValue(0).toInt();
}

Qt 4.6.0 & 4.6.1: execution was OK, ID was printed out, but at the end of the block program crashed in QSqlQuery destructor somewhere in libqsqlodbc.so when the array of QVariant* was deleted.

Qt 4.5.3: program crashed in query.exec() -> QODBCResult::exec() -> ->QVector<QVariant>::realloc(int,int) -> QVariant::QVariant(QVariant const &)

Do you have any explanation for this thing?

wysota
22nd January 2010, 12:11
We'd have to see the bigger picture. Is your application multithreaded?

seim
22nd January 2010, 13:04
The code can be simplified with the same results to

int main( int argc, char *argv[] )
{
QApplication app( argc, argv, FALSE );

QSqlDatabase db = QSqlDatabase::addDatabase( DB_DRIVER );
db.setDatabaseName( DB_DBNAME );
db.setUserName( DB_USER );
db.setPassword( DB_PASSWD );
db.setHostName( DB_HOST );

if (db.open())
{
QSqlQuery query;
query.prepare("{call dbo.proc03test(?);}");
query.bindValue(0, 1, QSql::Out);
qDebug() << query.exec(); // Qt 4.5.3-r2, Qt 4.5.3
qDebug() << "Output ID = " << query.boundValue(0).toInt();
} // Qt 4.6 crash
}

I've tried different Qt versions, different linux systems (gentoo - stable/unstable system libraries) with the same results.
There is no problem if only input parameters are used, or if the results are retrieved via query without any preparation.

The code can be rewritten in following way, but it comes me as closing eyes, I would like to know why it is falling down
and be sure, that all components are all right and the error will not appear later in different cases..


QSqlQuery query;
query.prepare(
"DECLARE @return_value int, @id int; \n"
"EXEC @return_value = [dbo].[proc03test] @id = @id OUTPUT; \n"
"SELECT @id, @return_value;"
);
qDebug() << query.exec();
QSqlRecord rec = query.record();

qDebug() << "Columns: " << rec.count();
while (query.next())
qDebug() << query.value(0).toInt()
<< query.value(1).toInt();


Note: tests were made on Gentoo Linux x86_64

wysota
22nd January 2010, 14:39
What about calling query.next() first before accessing the value? By the way, your "1" is ignored if you set the type of binding to "Out".

seim
22nd January 2010, 14:46
Shame on me!! MSSQL via ODBC needs setForwardOnly(true) also for stored procedures..


...
QSqlQuery query;
query.setForwardOnly(true);
query.prepare("{? = call dbo.proc03test(?);}");
...

soxs060389
22nd January 2010, 23:12
+1 to waysotas post, see doc