Initialize the QSqlQuery to be invalid when creating a sql model
When QSqlQueryModel or QSqlTableModel is created it will create a QSqlQuery which defaults to using the default QSqlDatabase connection. If this connection belongs to another thread then it will throw a warning as this is not safe to use. Since the QSqlQuery is always recreated when a query is set, the instance which is a member of the class can effectively be invalid until a new one is set. Task-number: QTBUG-69213 Change-Id: I68a5dd59fe62788f531d59a0680da11b118ee383 Reviewed-by: Christian Ehrlicher <ch.ehrlicher@gmx.de> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
parent
fbb4befa33
commit
28702cb239
@ -75,7 +75,7 @@ public:
|
|||||||
void initColOffsets(int size);
|
void initColOffsets(int size);
|
||||||
int columnInQuery(int modelColumn) const;
|
int columnInQuery(int modelColumn) const;
|
||||||
|
|
||||||
mutable QSqlQuery query;
|
mutable QSqlQuery query = { QSqlQuery(0) };
|
||||||
mutable QSqlError error;
|
mutable QSqlError error;
|
||||||
QModelIndex bottom;
|
QModelIndex bottom;
|
||||||
QSqlRecord rec;
|
QSqlRecord rec;
|
||||||
|
@ -93,7 +93,7 @@ public:
|
|||||||
QSqlTableModel::EditStrategy strategy;
|
QSqlTableModel::EditStrategy strategy;
|
||||||
bool busyInsertingRows;
|
bool busyInsertingRows;
|
||||||
|
|
||||||
QSqlQuery editQuery;
|
QSqlQuery editQuery = { QSqlQuery(0) };
|
||||||
QSqlIndex primaryIndex;
|
QSqlIndex primaryIndex;
|
||||||
QString tableName;
|
QString tableName;
|
||||||
QString filter;
|
QString filter;
|
||||||
|
@ -31,11 +31,29 @@
|
|||||||
#include "../../kernel/qsqldatabase/tst_databases.h"
|
#include "../../kernel/qsqldatabase/tst_databases.h"
|
||||||
#include <QtSql>
|
#include <QtSql>
|
||||||
#include <QtSql/private/qsqltablemodel_p.h>
|
#include <QtSql/private/qsqltablemodel_p.h>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
const QString test(qTableName("test", __FILE__, QSqlDatabase())),
|
const QString test(qTableName("test", __FILE__, QSqlDatabase())),
|
||||||
test2(qTableName("test2", __FILE__, QSqlDatabase())),
|
test2(qTableName("test2", __FILE__, QSqlDatabase())),
|
||||||
test3(qTableName("test3", __FILE__, QSqlDatabase()));
|
test3(qTableName("test3", __FILE__, QSqlDatabase()));
|
||||||
|
|
||||||
|
// In order to catch when the warning message occurs, indicating that the database belongs to another
|
||||||
|
// thread, we have to install our own message handler. To ensure that the test reporting still happens
|
||||||
|
// as before, we call the originating one.
|
||||||
|
//
|
||||||
|
// For now, this is only called inside the modelInAnotherThread() test
|
||||||
|
QtMessageHandler oldHandler = nullptr;
|
||||||
|
|
||||||
|
void sqlTableModelMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||||
|
{
|
||||||
|
if (type == QtWarningMsg &&
|
||||||
|
msg == "QSqlDatabasePrivate::database: requested database does not "
|
||||||
|
"belong to the calling thread.") {
|
||||||
|
QFAIL("Requested database does not belong to the calling thread.");
|
||||||
|
}
|
||||||
|
if (oldHandler)
|
||||||
|
oldHandler(type, context, msg);
|
||||||
|
}
|
||||||
|
|
||||||
class tst_QSqlTableModel : public QObject
|
class tst_QSqlTableModel : public QObject
|
||||||
{
|
{
|
||||||
@ -116,6 +134,7 @@ private slots:
|
|||||||
|
|
||||||
void sqlite_bigTable_data() { generic_data("QSQLITE"); }
|
void sqlite_bigTable_data() { generic_data("QSQLITE"); }
|
||||||
void sqlite_bigTable();
|
void sqlite_bigTable();
|
||||||
|
void modelInAnotherThread();
|
||||||
|
|
||||||
// bug specific tests
|
// bug specific tests
|
||||||
void insertRecordBeforeSelect_data() { generic_data(); }
|
void insertRecordBeforeSelect_data() { generic_data(); }
|
||||||
@ -276,6 +295,10 @@ void tst_QSqlTableModel::init()
|
|||||||
void tst_QSqlTableModel::cleanup()
|
void tst_QSqlTableModel::cleanup()
|
||||||
{
|
{
|
||||||
recreateTestTables();
|
recreateTestTables();
|
||||||
|
if (oldHandler) {
|
||||||
|
qInstallMessageHandler(oldHandler);
|
||||||
|
oldHandler = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tst_QSqlTableModel::select()
|
void tst_QSqlTableModel::select()
|
||||||
@ -2100,5 +2123,29 @@ void tst_QSqlTableModel::invalidFilterAndHeaderData()
|
|||||||
QVERIFY(!v.isValid());
|
QVERIFY(!v.isValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SqlThread : public QThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SqlThread() : QThread() {}
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "non-default-connection");
|
||||||
|
QSqlTableModel stm(nullptr, db);
|
||||||
|
isDone = true;
|
||||||
|
}
|
||||||
|
bool isDone = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_QSqlTableModel::modelInAnotherThread()
|
||||||
|
{
|
||||||
|
oldHandler = qInstallMessageHandler(sqlTableModelMessageHandler);
|
||||||
|
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
|
||||||
|
CHECK_DATABASE(db);
|
||||||
|
SqlThread t;
|
||||||
|
t.start();
|
||||||
|
QTRY_VERIFY(t.isDone);
|
||||||
|
QVERIFY(t.isFinished());
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QSqlTableModel)
|
QTEST_MAIN(tst_QSqlTableModel)
|
||||||
#include "tst_qsqltablemodel.moc"
|
#include "tst_qsqltablemodel.moc"
|
||||||
|
Loading…
Reference in New Issue
Block a user