sqlite: Bind duplicated named placeholders correctly

sqlite will reuse the index for bound parameters when the named
placeholder is duplicated so we only need to call bind one time for each
placeholder. Therefore we need to have just one instance of each value
when doing the bind.

Task-number: QTBUG-65150
Change-Id: I75c4bcc4563e43c180a59a7a4cbb770dbe994642
Reviewed-by: Jesus Fernandez <Jesus.Fernandez@qt.io>
This commit is contained in:
Andy Shaw 2018-01-02 09:33:48 +01:00
parent 24fba6744c
commit 3e58f2b090
2 changed files with 40 additions and 1 deletions

View File

@ -446,7 +446,7 @@ static QString timespecToString(const QDateTime &dateTime)
bool QSQLiteResult::exec()
{
Q_D(QSQLiteResult);
const QVector<QVariant> values = boundValues();
QVector<QVariant> values = boundValues();
d->skippedStatus = false;
d->skipRow = false;
@ -478,6 +478,20 @@ bool QSQLiteResult::exec()
countIndexes);
paramCountIsValid = bindParamCount == values.count();
// When using named placeholders, it will reuse the index for duplicated
// placeholders. So we need to ensure the QVector has only one instance of
// each value as SQLite will do the rest for us.
QVector<QVariant> prunedValues;
QList<int> handledIndexes;
for (int i = 0, currentIndex = 0; i < values.size(); ++i) {
if (handledIndexes.contains(i))
continue;
const auto placeHolder = QString::fromUtf8(sqlite3_bind_parameter_name(d->stmt, currentIndex + 1));
handledIndexes << d->indexes[placeHolder];
prunedValues << values.at(d->indexes[placeHolder].first());
++currentIndex;
}
values = prunedValues;
}
#endif

View File

@ -2017,6 +2017,31 @@ void tst_QSqlQuery::prepare_bind_exec()
QCOMPARE( q.value(1).toString(), QString("name") );
QCOMPARE( q.value(2).toString(), QString("name") );
// Test that duplicated named placeholders before the next unique one works correctly - QTBUG-65150
QVERIFY(q.prepare("insert into " + qtest_prepare + " (id, name, name2) values (:id, :id, :name)"));
for (i = 104; i < 106; ++i) {
q.bindValue(":id", i);
q.bindValue(":name", "name");
QVERIFY(q.exec());
}
QVERIFY(q.exec("select * from " + qtest_prepare + " where id > 103 order by id"));
QVERIFY(q.next());
QCOMPARE(q.value(0).toInt(), 104);
QCOMPARE(q.value(1).toString(), QString("104"));
QCOMPARE(q.value(2).toString(), QString("name"));
// Test that duplicated named placeholders in any order
QVERIFY(q.prepare("insert into " + qtest_prepare + " (id, name, name2) values (:id, :name, :id)"));
for (i = 107; i < 109; ++i) {
q.bindValue(":id", i);
q.bindValue(":name", "name");
QVERIFY(q.exec());
}
QVERIFY(q.exec("select * from " + qtest_prepare + " where id > 106 order by id"));
QVERIFY(q.next());
QCOMPARE(q.value(0).toInt(), 107);
QCOMPARE(q.value(1).toString(), QString("name"));
QCOMPARE(q.value(2).toString(), QString("107"));
} // end of SQLite scope
}