QString executedQuery;
QHash<int, QSql::ParamType> types;
QVector<QVariant> values;
- typedef QHash<QString, int> IndexMap;
+ typedef QHash<QString, QList<int> > IndexMap;
IndexMap indexes;
typedef QVector<QHolder> QHolderVector;
QHolderVector holders;
};
+static QString qFieldSerial(int);
+
QString QSqlResultPrivate::holderAt(int index) const
{
- return indexes.key(index);
+ return holders.size() > index ? holders.at(index).holderName : qFieldSerial(index);
}
// return a unique id for bound names
for (int i = 0; i < n; ++i) {
QChar ch = sql.at(i);
if (ch == QLatin1Char('?') && !inQuote) {
+ // Update the holder position since we are changing the holder name lengths
+ holders[count].holderPos = result.size();
result += qFieldSerial(count++);
} else {
if (ch == QLatin1Char('\''))
int pos = i + 2;
while (pos < n && qIsAlnum(sql.at(pos)))
++pos;
- indexes[sql.mid(i, pos - i)] = count++;
+ QString holder(sql.mid(i, pos - i));
+ indexes[holder].append(count++);
+ holders.append(QHolder(holder, i));
result += QLatin1Char('?');
i = pos;
} else {
}
}
result.squeeze();
+ values.resize(holders.size());
return result;
}
*/
bool QSqlResult::prepare(const QString& query)
{
- int n = query.size();
+ if (d->holders.isEmpty()) {
+ int n = query.size();
- bool inQuote = false;
- int i = 0;
-
- while (i < n) {
- QChar ch = query.at(i);
- if (ch == QLatin1Char(':') && !inQuote
- && (i == 0 || query.at(i - 1) != QLatin1Char(':'))
- && (i + 1 < n && qIsAlnum(query.at(i + 1)))) {
- int pos = i + 2;
- while (pos < n && qIsAlnum(query.at(pos)))
- ++pos;
+ bool inQuote = false;
+ int i = 0;
- d->holders.append(QHolder(query.mid(i, pos - i), i));
- i = pos;
- } else {
- if (ch == QLatin1Char('\''))
- inQuote = !inQuote;
- ++i;
+ while (i < n) {
+ QChar ch = query.at(i);
+ if (ch == QLatin1Char(':') && !inQuote
+ && (i == 0 || query.at(i - 1) != QLatin1Char(':'))
+ && (i + 1 < n && qIsAlnum(query.at(i + 1)))) {
+ int pos = i + 2;
+ while (pos < n && qIsAlnum(query.at(pos)))
+ ++pos;
+
+ QString holder(query.mid(i, pos - i));
+ d->indexes[holder].append(d->holders.size());
+ d->holders.append(QHolder(holder, i));
+ i = pos;
+ } else {
+ if (ch == QLatin1Char('\''))
+ inQuote = !inQuote;
+ ++i;
+ }
}
+ d->values.resize(d->holders.size());
}
d->sql = query;
return true; // fake prepares should always succeed
QString holder;
for (i = d->holders.count() - 1; i >= 0; --i) {
holder = d->holders.at(i).holderName;
- val = d->values.value(d->indexes.value(holder));
+ val = d->values.value(d->indexes.value(holder).value(0,-1));
QSqlField f(QLatin1String(""), val.type());
f.setValue(val);
query = query.replace(d->holders.at(i).holderPos,
void QSqlResult::bindValue(int index, const QVariant& val, QSql::ParamType paramType)
{
d->binds = PositionalBinding;
- d->indexes[qFieldSerial(index)] = index;
+ d->indexes[qFieldSerial(index)].append(index);
if (d->values.count() <= index)
d->values.resize(index + 1);
d->values[index] = val;
d->binds = NamedBinding;
// if the index has already been set when doing emulated named
// bindings - don't reset it
- int idx = d->indexes.value(placeholder, -1);
- if (idx >= 0) {
+ QList<int> indexes = d->indexes.value(placeholder);
+ foreach (int idx, indexes) {
if (d->values.count() <= idx)
d->values.resize(idx + 1);
d->values[idx] = val;
- } else {
- d->values.append(val);
- idx = d->values.count() - 1;
- d->indexes[placeholder] = idx;
+ if (paramType != QSql::In || !d->types.isEmpty())
+ d->types[idx] = paramType;
}
-
- if (paramType != QSql::In || !d->types.isEmpty())
- d->types[idx] = paramType;
}
/*!
*/
QVariant QSqlResult::boundValue(const QString& placeholder) const
{
- int idx = d->indexes.value(placeholder, -1);
- return d->values.value(idx);
+ QList<int> indexes = d->indexes.value(placeholder);
+ return d->values.value(indexes.value(0,-1));
}
/*!
*/
QSql::ParamType QSqlResult::bindValueType(const QString& placeholder) const
{
- return d->types.value(d->indexes.value(placeholder, -1), QSql::In);
+ return d->types.value(d->indexes.value(placeholder).value(0,-1), QSql::In);
}
/*!
QVERIFY_SQL( q, exec("set client_min_messages='warning'"));
if ( tst_Databases::isSqlServer( db ) || db.driverName().startsWith( "QTDS" ) )
- createQuery = "create table " + qtest_prepare + " (id int primary key, name nvarchar(200) null)";
+ createQuery = "create table " + qtest_prepare + " (id int primary key, name nvarchar(200) null, name2 nvarchar(200) null)";
else if ( tst_Databases::isMySQL(db) && useUnicode )
- createQuery = "create table " + qtest_prepare + " (id int not null primary key, name varchar(200) character set utf8)";
+ createQuery = "create table " + qtest_prepare + " (id int not null primary key, name varchar(200) character set utf8, name2 varchar(200) character set utf8)";
else
- createQuery = "create table " + qtest_prepare + " (id int not null primary key, name varchar(200))";
+ createQuery = "create table " + qtest_prepare + " (id int not null primary key, name varchar(200), name2 varchar(200))";
QVERIFY_SQL( q, exec( createQuery ) );
QCOMPARE( q.value( 0 ).toInt(), i );
QCOMPARE( q.value( 1 ).toString().trimmed(), values[ i ] );
QSqlRecord rInf = q.record();
- QCOMPARE(( int )rInf.count(), 2 );
+ QCOMPARE(( int )rInf.count(), 3 );
QCOMPARE( rInf.field( 0 ).name().toUpper(), QString( "ID" ) );
QCOMPARE( rInf.field( 1 ).name().toUpper(), QString( "NAME" ) );
QVERIFY( !q.next() );
QVERIFY( !q.isActive() );
+ QVERIFY( q.prepare( "insert into " + qtest_prepare + " (id, name, name2) values (:id, :name, :name)" ) );
+ for ( i = 101; i < 103; ++i ) {
+ q.bindValue( ":id", i );
+ q.bindValue( ":name", "name" );
+ QVERIFY( q.exec() );
+ }
+
+ // Test for QTBUG-6420
+ QVERIFY( q.exec( "select * from " + qtest_prepare + " where id > 100 order by id" ) );
+ QVERIFY( q.next() );
+ QCOMPARE( q.value(0).toInt(), 101 );
+ QCOMPARE( q.value(1).toString(), QString("name") );
+ QCOMPARE( q.value(2).toString(), QString("name") );
+
} // end of SQLite scope
}