QSqlQueryModel & QSqlQuery::prepare - app crash
-
Hi and welcome to devnet,
It would be even better if you could attach a minimal compilable example to your bug report, if possible with a minimal SQL dump file to recreate the database so it's possible to try and reproduce your crash more easily
-
I found out, that the error is triggered when I have this line:
@QSqlDatabase::removeDatabase(QSqlDatabase::database().connectionName());@in my MainWindow::~MainWindow (destructor). Executing this line writes this:
bq. QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
And next - the error is triggered. I heve just posted the code example to the bugreport (QTBUG-43889) .
Is it sufficient to just call
@QSqlDatabase::database().close();@to properly free the connection? Maybe I don't need to call QSqlDatabase::removeDatabase ?
-
Hi,
try this in the destructor:
@
yourDatabase = QSqlDatabase();
QSqlDatabase::removeDatabase(yourDatabase.connectionName());
@ -
[quote author="Clochydd" date="1422090466"]Hi,
try this in the destructor:
@
yourDatabase = QSqlDatabase();
QSqlDatabase::removeDatabase(yourDatabase.connectionName());
@
[/quote]Tried it - no effect:
@dbTestGUI::~dbTestGUI()
{
QSqlDatabase db = QSqlDatabase::database();
//db.close();
QSqlDatabase::removeDatabase(db.connectionName()); //this line causes error
}@ -
Hi,
I always open my databases that way:
@
db = QSqlDatabase::addDatabase("QPSQL");
db.setDatabaseName("myDB");
db.setHostName("localhost");
db.setPort(5432);
if (!db.open("user", "password")) {
...
}
...
@and close it the destructor:
@
db = QSqlDatabase();
QSqlDatabase::removeDatabase(db.connectionName());
@ -
According to the doc:
bq. QSqlDatabase::QSqlDatabase()
Creates an empty, invalid QSqlDatabase object. Use addDatabase(), removeDatabase(), and database() to get valid QSqlDatabase objects.So I guess that you remove an invalid database - which probably doesn't do anything at all...
-
As i thought - when using your code - nothing happens. Neither is the connection closed (I can still see it it PgAdmin's "server status window":http://www.pgadmin.org/docs/dev/status.html), nor are the dll's unloaded. So I guess - that you'have been always closing it the wrong way :)
-
Just checked with pgAdmin's server status:
The connection appears when any of my postgres based programs is opened and disappears when the program is closed...I came to the above described solution after several weeks of trial and error and with support by this forum.
-
Well, yes. The connection is created when you call QSqlDatabase::open. And it is closed as the application is closed - even if you don't call anything in the destructor. What I meant, is that if you execute and debug your code line-by-line - it does nothing.
Consider the following:
@dbTestGUI::~dbTestGUI()
{
QSqlDatabase db = QSqlDatabase();
qDebug() << db.isValid(); //returns false
db.close(); //does nothing - connection still visible in pgadmin server status
QSqlDatabase::removeDatabase(db.connectionName()); does nothig - no effect visible
}@versus:
@dbTestGUI::~dbTestGUI()
{
QSqlDatabase db = QSqlDatabase().database();
qDebug() << db.isValid(); //returns true
db.close(); //connection disappears from server status
QSqlDatabase::removeDatabase(db.connectionName()); // sometimes some DLL's get unloaded, sometimest not.
//the following line appears on the console: "QSqlDatabasePrivate::removeDatabase: connection ‘qt_sql_default_connection’ is still in use, all queries will cease to work."
}@When run the app, after executing this destructor it crashes. But when i comment the line:
@QSqlDatabase::removeDatabase(db.connectionName()); @it doesn't
-
So, to sum up - this is my destructor now:
@dbTestGUI::~dbTestGUI()
{
QSqlDatabase db = QSqlDatabase().database();
qDebug() << db.isValid();
db.close();
//QSqlDatabase::removeDatabase(db.connectionName()); //this line results in error after executing the d-tor
}@
when stepping out of it, I get the following message:bq. Unable to free statement: connection pointer is NULL
So i guess, that Qt has a general problem with free'ing Prepared Statemets. Probably, because on one hand the QSqlQuery object is copied to the model (via QSqlQueryModel::setQuery), ant on the other hand QSqlQuery's parent is QSqlDatabase:
@QSqlQuery::QSqlQuery(const QString & query = QString(), QSqlDatabase db = QSqlDatabase()) @So instead of deallocating the query when the model is deleted - it is dealocated, when the database object gets destroyed.
-
I guess I solved it. When the model is initialized as view's child:
@model = new QSqlQueryModel(this);@
The problem is order of operations. When I close the connection and remove the database in the destructor of my class - the database gets disconnected and no further operations are possible. But after my class' destructor, destructors of its base classes get into action - one by another, as ordered by inheritance. When Qobject::~Qobject() is executed, it gets to the
@QObjectPrivate::deleteChildren() @method. And then, it finally gets to delete the model. The model wants to free the resources - which means QSqlResult (QPSQLResult to be specific in that case). This it how it looks:
@QPSQLResult::~QPSQLResult()
{
Q_D(QPSQLResult);
cleanup();if (d->preparedQueriesEnabled && !d->preparedStmtId.isNull()) d->deallocatePreparedStmt();
}@
So here Qt tries to deallocate preparedStatement - regardless of the fact, that the connection no longer exists:
@void QPSQLResultPrivate::deallocatePreparedStmt()
{
const QString stmt = QLatin1String("DEALLOCATE ") + preparedStmtId;
PGresult *result = privDriver()->exec(stmt);if (PQresultStatus(result) != PGRES_COMMAND_OK) qWarning("Unable to free statement: %s", PQerrorMessage(privDriver()->connection)); PQclear(result); preparedStmtId.clear();
}@
So - to make it work properly, I wolud have to call
@QSqlQueryModel::~QSqlQueryModel() @or
@QSqlQueryModel::clear()@BEFORE closing the connection with the DB. I still think it's a bug.