Skip to content

Commit

Permalink
sqlite: Prevent a crash when sqlite does not detect any parameters
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Edward Welbourne <[email protected]>
  • Loading branch information
AndyShawQt committed Mar 17, 2018
1 parent f6f4001 commit e4e87a2
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
};
Expand Down
41 changes: 41 additions & 0 deletions tests/auto/sql/kernel/qsqlquery/tst_qsqlquery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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"

0 comments on commit e4e87a2

Please sign in to comment.