summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHonglei Zhang <honglei.zhang@nokia.com>2011-12-08 12:17:08 (GMT)
committerQt by Nokia <qt-info@nokia.com>2012-04-03 06:51:58 (GMT)
commit8cd69eb1ffd37194e3d736a3bb5ce8511b8b8854 (patch)
tree56e5a299418ed3ef2bc55f876c6c74600933d22c
parentcdc1720730dff64ef61e4cb9457c46dae8101315 (diff)
downloadQt-8cd69eb1ffd37194e3d736a3bb5ce8511b8b8854.zip
Qt-8cd69eb1ffd37194e3d736a3bb5ce8511b8b8854.tar.gz
Qt-8cd69eb1ffd37194e3d736a3bb5ce8511b8b8854.tar.bz2
Memory leak fix of sqlite driver when close failed
If an ongoing query is not finalized before close function is called, sqlite driver can't close the connection to sqlite. In this case, the failure is only reported to the client via getLastError(). Even if the client want to handle this case, there is no easy way to revoke the close function. This commit finalizes all queries before close is called. Task-number: QTBUG-16967 Change-Id: I069f6073bd46f53780e13d269e44aa86366e0574 Reviewed-by: Andy Shaw <andy.shaw@digia.com> Reviewed-by: Mark Brand <mabrand@mabrand.nl>
-rw-r--r--src/sql/drivers/sqlite/qsql_sqlite.cpp8
-rw-r--r--src/sql/kernel/qsqlresult.cpp7
-rw-r--r--tests/auto/qsqlquery/tst_qsqlquery.cpp54
3 files changed, 66 insertions, 3 deletions
diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp
index 97d3531..e95b794 100644
--- a/src/sql/drivers/sqlite/qsql_sqlite.cpp
+++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp
@@ -105,6 +105,7 @@ class QSQLiteDriverPrivate
public:
inline QSQLiteDriverPrivate() : access(0) {}
sqlite3 *access;
+ QList <QSQLiteResult *> results;
};
@@ -312,10 +313,14 @@ QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db)
{
d = new QSQLiteResultPrivate(this);
d->access = db->d->access;
+ db->d->results.append(this);
}
QSQLiteResult::~QSQLiteResult()
{
+ const QSQLiteDriver * sqlDriver = qobject_cast<const QSQLiteDriver *>(driver());
+ if (sqlDriver)
+ sqlDriver->d->results.removeOne(this);
d->cleanup();
delete d;
}
@@ -579,6 +584,9 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
void QSQLiteDriver::close()
{
if (isOpen()) {
+ foreach (QSQLiteResult *result, d->results)
+ result->d->finalize();
+
if (sqlite3_close(d->access) != SQLITE_OK)
setLastError(qMakeError(d->access, tr("Error closing database"),
QSqlError::ConnectionError));
diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp
index 4aeae1f..de348c9 100644
--- a/src/sql/kernel/qsqlresult.cpp
+++ b/src/sql/kernel/qsqlresult.cpp
@@ -48,6 +48,7 @@
#include "qsqlresult.h"
#include "qvector.h"
#include "qsqldriver.h"
+#include "qpointer.h"
#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -64,7 +65,7 @@ class QSqlResultPrivate
{
public:
QSqlResultPrivate(QSqlResult* d)
- : q(d), sqldriver(0), idx(QSql::BeforeFirstRow), active(false),
+ : q(d), idx(QSql::BeforeFirstRow), active(false),
isSel(false), forwardOnly(false), precisionPolicy(QSql::LowPrecisionDouble), bindCount(0), binds(QSqlResult::PositionalBinding)
{}
@@ -98,7 +99,7 @@ public:
public:
QSqlResult* q;
- const QSqlDriver* sqldriver;
+ QPointer<QSqlDriver> sqldriver;
int idx;
QString sql;
bool active;
@@ -250,7 +251,7 @@ QString QSqlResultPrivate::namedToPositionalBinding()
QSqlResult::QSqlResult(const QSqlDriver *db)
{
d = new QSqlResultPrivate(this);
- d->sqldriver = db;
+ d->sqldriver = const_cast<QSqlDriver *>(db);
if(db) {
setNumericalPrecisionPolicy(db->numericalPrecisionPolicy());
}
diff --git a/tests/auto/qsqlquery/tst_qsqlquery.cpp b/tests/auto/qsqlquery/tst_qsqlquery.cpp
index 147bbe1..4355242 100644
--- a/tests/auto/qsqlquery/tst_qsqlquery.cpp
+++ b/tests/auto/qsqlquery/tst_qsqlquery.cpp
@@ -215,6 +215,8 @@ private slots:
void QTBUG_14132();
void QTBUG_21884_data() { generic_data("QSQLITE"); }
void QTBUG_21884();
+ void QTBUG_16967_data() { generic_data("QSQLITE"); }
+ void QTBUG_16967(); //clean close
void sqlite_constraint_data() { generic_data("QSQLITE"); }
void sqlite_constraint();
@@ -3150,6 +3152,58 @@ void tst_QSqlQuery::QTBUG_21884()
}
}
+/**
+ * This test case test sqlite driver close function. Sqlite driver should close cleanly
+ * even if there is still outstanding prepared statement.
+ */
+void tst_QSqlQuery::QTBUG_16967()
+{
+ QSqlQuery q2;
+ QFETCH(QString, dbName);
+ {
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ CHECK_DATABASE(db);
+ db.close();
+ QCOMPARE(db.lastError().type(), QSqlError::NoError);
+ }
+ {
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ CHECK_DATABASE(db);
+ QSqlQuery q(db);
+ q2 = q;
+ q.prepare("CREATE TABLE t1 (id INTEGER PRIMARY KEY, str TEXT);");
+ db.close();
+ QCOMPARE(db.lastError().type(), QSqlError::NoError);
+ }
+ {
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ CHECK_DATABASE(db);
+ QSqlQuery q(db);
+ q2 = q;
+ q2.prepare("CREATE TABLE t1 (id INTEGER PRIMARY KEY, str TEXT);");
+ q2.exec();
+ db.close();
+ QCOMPARE(db.lastError().type(), QSqlError::NoError);
+ }
+ {
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ CHECK_DATABASE(db);
+ QSqlQuery q(db);
+ q2 = q;
+ q.exec("INSERT INTO t1 (id, str) VALUES(1, \"test1\");");
+ db.close();
+ QCOMPARE(db.lastError().type(), QSqlError::NoError);
+ }
+ {
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ CHECK_DATABASE(db);
+ QSqlQuery q(db);
+ q2 = q;
+ q2.exec("SELECT * FROM t1;");
+ db.close();
+ QCOMPARE(db.lastError().type(), QSqlError::NoError);
+ }
+}
void tst_QSqlQuery::oraOCINumber()
{