Change boundValues() to return a QVariantList

This enables the order of boundValues to be consistent as with a QMap
it could have been reordered which can be a problem for positional
bindings.

[ChangeLog][QtSQL] Changed signature of QSqlQuery::boundValues() to
return a QVariantList

Fixes: QTBUG-51609
Change-Id: I1c80fa8522fa7352723420b6fc9ec466406315fb
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Andy Shaw 2020-06-11 10:49:50 +02:00
parent 590ac717a2
commit 8ba9d2e022
5 changed files with 127 additions and 74 deletions

View File

@ -50,7 +50,6 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QtSql> #include <QtSql>
#include <QMap>
#include <iostream> #include <iostream>
using namespace std; using namespace std;
@ -202,23 +201,12 @@ void QSqlQuery_snippets()
QSqlQuery query; QSqlQuery query;
{ {
// examine with named binding // examine with named or positional binding
//! [14] //! [14]
QMap<QString, QVariant> sqlIterator(query.boundValues()); QVariantList list = query.boundValues();
for (auto i = sqlIterator.begin(); i != sqlIterator.end(); ++i) {
cout << i.key().toUtf8().data() << ": "
<< i.value().toString().toUtf8().data() << "\n";
}
//! [14]
}
{
// examine with positional binding
//! [15]
QList<QVariant> list = query.boundValues().values();
for (int i = 0; i < list.size(); ++i) for (int i = 0; i < list.size(); ++i)
cout << i << ": " << list.at(i).toString().toUtf8().data() << "\n"; cout << i << ": " << list.at(i).toString().toUtf8().data() << "\n";
//! [15] //! [14]
} }
} }

View File

@ -0,0 +1,66 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\page qtsql-changes-qt6.html
\title Porting to Qt 6 - Qt Sql
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
We try to maintain binary and source compatibility for all the public
APIs in each release. But some changes were inevitable in an effort to
make Qt a better framework.
In this topic we summarize those changes in Qt Sql, and provide guidance
to handle them.
\section1 QSqlQuery
\section2 boundValues() Signature
The return type for boundValues() has been changed from QMap<QString, QVariant>
to a QVariantList. The order can be relied upon so it will be in the order of the
binding in the prepared query. Change code like the following:
\code
QMap<QString, QVariant> values = boundValues();
int id = values[":id"].value().toInt();
\endcode
\code
QList<QVariant> values = boundValues().values();
int id = values.at(0).toInt();
\endcode
to:
\code
QList<QVariant> values = boundValues().values();
int id = values.at(0).toInt();
\endcode
*/

View File

@ -180,7 +180,7 @@ QSqlQueryPrivate::~QSqlQueryPrivate()
them in the same query. them in the same query.
You can retrieve the values of all the fields in a single variable You can retrieve the values of all the fields in a single variable
(a map) using boundValues(). using boundValues().
\note Not all SQL operations support binding values. Refer to your database \note Not all SQL operations support binding values. Refer to your database
system's documentation to check their availability. system's documentation to check their availability.
@ -1144,27 +1144,24 @@ QVariant QSqlQuery::boundValue(int pos) const
} }
/*! /*!
Returns a map of the bound values. \since 6.0
With named binding, the bound values can be examined in the Returns a list of bound values.
following ways:
The order of the list is in binding order, irrespective of whether
named or positional binding is used.
The bound values can be examined in the following way:
\snippet sqldatabase/sqldatabase.cpp 14 \snippet sqldatabase/sqldatabase.cpp 14
With positional binding, the code becomes:
\snippet sqldatabase/sqldatabase.cpp 15
\sa boundValue(), bindValue(), addBindValue() \sa boundValue(), bindValue(), addBindValue()
*/ */
QMap<QString,QVariant> QSqlQuery::boundValues() const
{
QMap<QString,QVariant> map;
const QVector<QVariant> values(d->sqlResult->boundValues()); QVariantList QSqlQuery::boundValues() const
for (int i = 0; i < values.count(); ++i) {
map[d->sqlResult->boundValueName(i)] = values.at(i); const QVariantList values(d->sqlResult->boundValues());
return map; return values;
} }
/*! /*!

View File

@ -43,18 +43,18 @@
#include <QtSql/qtsqlglobal.h> #include <QtSql/qtsqlglobal.h>
#include <QtSql/qsqldatabase.h> #include <QtSql/qsqldatabase.h>
#include <QtCore/qstring.h> #include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QVariant;
class QSqlDriver; class QSqlDriver;
class QSqlError; class QSqlError;
class QSqlResult; class QSqlResult;
class QSqlRecord; class QSqlRecord;
template <class Key, class T> class QMap;
class QSqlQueryPrivate; class QSqlQueryPrivate;
class Q_SQL_EXPORT QSqlQuery class Q_SQL_EXPORT QSqlQuery
{ {
public: public:
@ -107,7 +107,7 @@ public:
void addBindValue(const QVariant& val, QSql::ParamType type = QSql::In); void addBindValue(const QVariant& val, QSql::ParamType type = QSql::In);
QVariant boundValue(const QString& placeholder) const; QVariant boundValue(const QString& placeholder) const;
QVariant boundValue(int pos) const; QVariant boundValue(int pos) const;
QMap<QString, QVariant> boundValues() const; QVariantList boundValues() const;
QString executedQuery() const; QString executedQuery() const;
QVariant lastInsertId() const; QVariant lastInsertId() const;
void finish(); void finish();

View File

@ -2100,10 +2100,10 @@ void tst_QSqlQuery::prepare_bind_exec()
q.bindValue( ":name", values[i] ); q.bindValue( ":name", values[i] );
q.bindValue( ":id", i ); q.bindValue( ":id", i );
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QMap<QString, QVariant> m = q.boundValues(); QVariantList m = q.boundValues();
QCOMPARE(( int ) m.count(), 2 ); QCOMPARE(( int ) m.count(), 2 );
QCOMPARE( m[":name"].toString(), values[i] ); QCOMPARE(m.at(0).toInt(), i);
QCOMPARE( m[":id"].toInt(), i ); QCOMPARE(m.at(1).toString(), values[i]);
} }
q.bindValue( ":id", 8 ); q.bindValue( ":id", 8 );
@ -2168,88 +2168,88 @@ void tst_QSqlQuery::prepare_bind_exec()
/*** Below we test QSqlQuery::boundValues() with position arguments. /*** Below we test QSqlQuery::boundValues() with position arguments.
* Due to the fact that the name of a positional argument is not * Due to the fact that the name of a positional argument is not
* specified by the Qt docs, we only test that the QMap contains * specified by the Qt docs, we test that the QVector contains
* the correct values and that QSqlResult::boundValueName returns * the correct values in the same order as QSqlResult::boundValueName
* the key that corrosponds to the correct value. ***/ * returns since it should be in insertion order (i.e. field order). ***/
QVERIFY( q.prepare( "insert into " + qtest_prepare + " (id, name) values (?, ?)" ) ); QVERIFY( q.prepare( "insert into " + qtest_prepare + " (id, name) values (?, ?)" ) );
q.bindValue( 0, 0 ); q.bindValue( 0, 0 );
q.bindValue( 1, values[ 0 ] ); q.bindValue( 1, values[ 0 ] );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 0); QCOMPARE(q.boundValues().at(0).toInt(), 0);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[0]); QCOMPARE(q.boundValues().at(1).toString(), values[0]);
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 0); QCOMPARE(q.boundValues().at(0).toInt(), 0);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[0]); QCOMPARE(q.boundValues().at(1).toString(), values[0]);
q.addBindValue( 1 ); q.addBindValue( 1 );
q.addBindValue( values[ 1 ] ); q.addBindValue( values[ 1 ] );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 1); QCOMPARE(q.boundValues().at(0).toInt(), 1);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[1]); QCOMPARE(q.boundValues().at(1).toString(), values[1]);
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 1); QCOMPARE(q.boundValues().at(0).toInt(), 1);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[1]); QCOMPARE(q.boundValues().at(1).toString(), values[1]);
q.addBindValue( 2 ); q.addBindValue( 2 );
q.addBindValue( values[ 2 ] ); q.addBindValue( values[ 2 ] );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 2); QCOMPARE(q.boundValues().at(0).toInt(), 2);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[2]); QCOMPARE(q.boundValues().at(1).toString(), values[2]);
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 2); QCOMPARE(q.boundValues().at(0).toInt(), 2);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[2]); QCOMPARE(q.boundValues().at(1).toString(), values[2]);
q.addBindValue( 3 ); q.addBindValue( 3 );
q.addBindValue( values[ 3 ] ); q.addBindValue( values[ 3 ] );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 3); QCOMPARE(q.boundValues().at(0).toInt(), 3);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[3]); QCOMPARE(q.boundValues().at(1).toString(), values[3]);
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 3); QCOMPARE(q.boundValues().at(0).toInt(), 3);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[3]); QCOMPARE(q.boundValues().at(1).toString(), values[3]);
q.addBindValue( 4 ); q.addBindValue( 4 );
q.addBindValue( values[ 4 ] ); q.addBindValue( values[ 4 ] );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 4); QCOMPARE(q.boundValues().at(0).toInt(), 4);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[4]); QCOMPARE(q.boundValues().at(1).toString(), values[4]);
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 4); QCOMPARE(q.boundValues().at(0).toInt(), 4);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[4]); QCOMPARE(q.boundValues().at(1).toString(), values[4]);
q.bindValue( 1, values[ 5 ] ); q.bindValue( 1, values[ 5 ] );
q.bindValue( 0, 5 ); q.bindValue( 0, 5 );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 5); QCOMPARE(q.boundValues().at(0).toInt(), 5);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[5]); QCOMPARE(q.boundValues().at(1).toString(), values[5]);
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 5); QCOMPARE(q.boundValues().at(0).toInt(), 5);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), values[5]); QCOMPARE(q.boundValues().at(1).toString(), values[5]);
q.bindValue( 0, 6 ); q.bindValue( 0, 6 );
q.bindValue( 1, QString() ); q.bindValue( 1, QString() );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 6); QCOMPARE(q.boundValues().at(0).toInt(), 6);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), QString()); QCOMPARE(q.boundValues().at(1).toString(), QString());
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QCOMPARE( q.boundValues().size(), 2 ); QCOMPARE( q.boundValues().size(), 2 );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 6); QCOMPARE(q.boundValues().at(0).toInt(), 6);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), QString()); QCOMPARE(q.boundValues().at(1).toString(), QString());
if ( db.driver()->hasFeature( QSqlDriver::Unicode ) ) { if ( db.driver()->hasFeature( QSqlDriver::Unicode ) ) {
q.bindValue( 0, 7 ); q.bindValue( 0, 7 );
q.bindValue( 1, utf8str ); q.bindValue( 1, utf8str );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 7); QCOMPARE(q.boundValues().at(0).toInt(), 7);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), utf8str); QCOMPARE(q.boundValues().at(1).toString(), utf8str);
QVERIFY_SQL( q, exec() ); QVERIFY_SQL( q, exec() );
QCOMPARE(q.boundValues()[q.result()->boundValueName(0)].toInt(), 7); QCOMPARE(q.boundValues().at(0).toInt(), 7);
QCOMPARE(q.boundValues()[q.result()->boundValueName(1)].toString(), utf8str); QCOMPARE(q.boundValues().at(1).toString(), utf8str);
} }
QVERIFY_SQL( q, exec( "SELECT * FROM " + qtest_prepare + " order by id" ) ); QVERIFY_SQL( q, exec( "SELECT * FROM " + qtest_prepare + " order by id" ) );
@ -3569,7 +3569,8 @@ void tst_QSqlQuery::QTBUG_551()
q.bindValue(":outp", outLst, QSql::Out); q.bindValue(":outp", outLst, QSql::Out);
QVERIFY_SQL(q, execBatch(QSqlQuery::ValuesAsColumns) ); QVERIFY_SQL(q, execBatch(QSqlQuery::ValuesAsColumns) );
res_outLst = qvariant_cast<QVariantList>(q.boundValues()[":outp"]); res_outLst = qvariant_cast<QVariantList>(q.boundValues().at(1));
QCOMPARE(res_outLst[0].toString(), QLatin1String("1. Value is 0")); QCOMPARE(res_outLst[0].toString(), QLatin1String("1. Value is 0"));
QCOMPARE(res_outLst[1].toString(), QLatin1String("2. Value is 1")); QCOMPARE(res_outLst[1].toString(), QLatin1String("2. Value is 1"));
QCOMPARE(res_outLst[2].toString(), QLatin1String("3. Value is 2")); QCOMPARE(res_outLst[2].toString(), QLatin1String("3. Value is 2"));
@ -3580,7 +3581,8 @@ void tst_QSqlQuery::QTBUG_12186()
QFETCH( QString, dbName ); QFETCH( QString, dbName );
QSqlDatabase db = QSqlDatabase::database(dbName); QSqlDatabase db = QSqlDatabase::database(dbName);
// make sure that query.boundValues() returns the values in the right order even for more than 16 placeholders // make sure that query.boundValues() returns the values in the right order
// even for more than 16 placeholders
QSqlQuery query(db); QSqlQuery query(db);
query.prepare("INSERT INTO person (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11, col12, col13, col14, col15, col16, col17, col18) " query.prepare("INSERT INTO person (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11, col12, col13, col14, col15, col16, col17, col18) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
@ -3593,7 +3595,7 @@ void tst_QSqlQuery::QTBUG_12186()
foreach (QVariant v, values) foreach (QVariant v, values)
query.bindValue(v.toInt(), v); query.bindValue(v.toInt(), v);
QCOMPARE(query.boundValues().values(), values); QCOMPARE(query.boundValues(), values);
} }
void tst_QSqlQuery::QTBUG_14132() void tst_QSqlQuery::QTBUG_14132()