summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Shaw <andy.shaw@qt.io>2018-03-07 15:12:13 +0100
committerAndy Shaw <andy.shaw@qt.io>2018-03-17 23:14:14 +0000
commite4e87a2ece1e0c9901514fea094f31863b64b570 (patch)
tree25990d2116e284790b4c95005dbe302e1f48f6d1
parentf6f40014c417aa90d4c805719e70910f522047e4 (diff)
sqlite: Prevent a crash when sqlite does not detect any parameters
When using a virtual table inside a SQLite database it is possible that it does not report the right number of parameters. Therefore we need to account for this case to prevent it from crashing when trying to bind parameters it thinks does not exist. Task-number: QTBUG-66816 Change-Id: I3ff70bb1fe73091f43c3df53616f75858e451cfd Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp5
-rw-r--r--tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp41
2 files changed, 45 insertions, 1 deletions
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
index d1a6582c5a..f715d3cba3 100644
--- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
@@ -467,7 +467,10 @@ bool QSQLiteResult::exec()
#if (SQLITE_VERSION_NUMBER >= 3003011)
// In the case of the reuse of a named placeholder
- if (paramCount < values.count()) {
+ // We need to check explicitly that paramCount is greater than 1, as sqlite
+ // can end up in a case where for virtual tables it returns 0 even though it
+ // has parameters
+ if (paramCount > 1 && paramCount < values.count()) {
const auto countIndexes = [](int counter, const QList<int>& indexList) {
return counter + indexList.length();
};
diff --git a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
index a51865897f..c4a27a3175 100644
--- a/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
+++ b/tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
@@ -176,6 +176,8 @@ private slots:
void emptyTableNavigate();
void timeStampParsing_data() { generic_data(); }
void timeStampParsing();
+ void sqliteVirtualTable_data() { generic_data("QSQLITE"); }
+ void sqliteVirtualTable();
#ifdef NOT_READY_YET
void task_229811();
@@ -4623,5 +4625,44 @@ void tst_QSqlQuery::dateTime()
}
}
+void tst_QSqlQuery::sqliteVirtualTable()
+{
+ // Virtual tables can behave differently when it comes to prepared
+ // queries, so we need to check these explicitly
+ QFETCH(QString, dbName);
+ QSqlDatabase db = QSqlDatabase::database(dbName);
+ CHECK_DATABASE(db);
+ const auto tableName = qTableName("sqliteVirtual", __FILE__, db);
+ QSqlQuery qry(db);
+ QVERIFY_SQL(qry, exec("create virtual table " + tableName + " using fts3(id, name)"));
+
+ // Delibrately malform the query to try and provoke a potential crash situation
+ QVERIFY_SQL(qry, prepare("select * from " + tableName + " where name match '?'"));
+ qry.addBindValue("Andy");
+ QVERIFY(!qry.exec());
+
+ QVERIFY_SQL(qry, prepare("insert into " + tableName + "(id, name) VALUES (?, ?)"));
+ qry.addBindValue(1);
+ qry.addBindValue("Andy");
+ QVERIFY_SQL(qry, exec());
+
+ QVERIFY_SQL(qry, exec("select * from " + tableName));
+ QVERIFY(qry.next());
+ QCOMPARE(qry.value(0).toInt(), 1);
+ QCOMPARE(qry.value(1).toString(), "Andy");
+
+ QVERIFY_SQL(qry, prepare("insert into " + tableName + "(id, name) values (:id, :name)"));
+ qry.bindValue(":id", 2);
+ qry.bindValue(":name", "Peter");
+ QVERIFY_SQL(qry, exec());
+
+ QVERIFY_SQL(qry, prepare("select * from " + tableName + " where name match ?"));
+ qry.addBindValue("Peter");
+ QVERIFY_SQL(qry, exec());
+ QVERIFY(qry.next());
+ QCOMPARE(qry.value(0).toInt(), 2);
+ QCOMPARE(qry.value(1).toString(), "Peter");
+}
+
QTEST_MAIN( tst_QSqlQuery )
#include "tst_qsqlquery.moc"